2012-03-16 15 views
31

Circular_buffer from boost library no es seguro para subprocesos. Así que envolví el objeto boost :: circular_buffer en una clase como se muestra a continuación. La exclusión mutua entre los hilos se logra (creo) mediante el uso de variables condicionales, un mutex y una adquisición/liberación de bloqueos. ¿Este hilo de implementación es seguro?Implementación segura de subprocesos de la memoria intermedia circular

#include <boost/thread/condition.hpp> 
#include <boost/thread/mutex.hpp> 
#include <boost/thread/thread.hpp> 
#include <boost/circular_buffer.hpp> 

// Thread safe circular buffer 
template <typename T> 
class circ_buffer : private boost::noncopyable 
{ 
public: 
    typedef boost::mutex::scoped_lock lock; 
    circ_buffer() {} 
    circ_buffer(int n) {cb.set_capacity(n);} 
    void send (T imdata) { 
     lock lk(monitor); 
     cb.push_back(imdata); 
     buffer_not_empty.notify_one(); 
    } 
    T receive() { 
     lock lk(monitor); 
     while (cb.empty()) 
      buffer_not_empty.wait(lk); 
     T imdata = cb.front(); 
     cb.pop_front(); 
     return imdata; 
    } 
    void clear() { 
     lock lk(monitor); 
     cb.clear(); 
    } 
    int size() { 
     lock lk(monitor); 
     return cb.size(); 
    } 
    void set_capacity(int capacity) { 
     lock lk(monitor); 
     cb.set_capacity(capacity); 
    } 
private: 
    boost::condition buffer_not_empty; 
    boost::mutex monitor; 
    boost::circular_buffer<T> cb; 
}; 

Editar Esto es ahora una clase de plantilla, que acepta un objeto de cualquier tipo (no sólo cv::Mat objeto).

+4

Parece que se ajustaría mejor en [CodeReview] (http://codereview.stackexchange.com/). –

+1

Perdona mi pregunta tonta, pero ¿dónde se necesita un búfer circular seguro de hilo? En todos los puntos en los que he usado un búfer circular, habría sido un grave error acceder a él desde varios hilos como este. Entonces, solo por curiosidad, ¿cuál es tu caso de uso para esto? – LiKao

+1

@LiKao Lo uso para tomar fotogramas de cámaras de red en MATLAB, ver mi publicación anterior http://stackoverflow.com/questions/9472880/how-to-implement-a-circular-buffer-of-cvmat-objects-opencv . ¿Cómo te acercarías a esto? – Alexey

Respuesta

16

Sí.
Si bloquea todos los métodos públicos con el mismo bloqueo, será seguro para la tarea.

Podría considerar el uso de read-write locks, que puede tener un mejor rendimiento si tiene muchos lectores simultáneos.

Si no tiene muchos lectores, solo agregará sobrecarga, pero puede valer la pena verificar la opción y las pruebas.

+10

No creo que los bloqueos de lectura y escritura tengan sentido en un búfer circular. Tanto los productores como los consumidores modifican el búfer, por lo que todos ellos son en realidad * escritores *. –

+0

@ DavidRodríguez-dribeas - Tienes razón en este caso.Realmente no entré en el diseño, solo la parte de seguridad del hilo. –

0

Se ve bien a primera vista, excepto que no está usando la condición buffer_not_full en absoluto. Es probable que desee agregar un código similar al código buffer_not_empty.

+1

Si una fuente de datos produce más datos de los que caben en la memoria intermedia, boost :: circular_buffer object escribe sobre los datos más antiguos. Esto esta bien. Por lo tanto, no es necesario comprobar la condición 'buffer_not_full'. – Alexey

5

creo que se ve bien, excepto que hay algunas copias inútiles de Mat realizadas en send. No necesita el nuevo, puede enviar directamente el argumento de send a su cb.

+0

+1 para evitar el copiado sin sentido, costoso y que aumenta la contención. –

+0

@MartinJames No puedo presionar directamente el argumento de enviar. "cv :: La clase Mat implementa el recuento de referencias y la copia superficial de modo que cuando una imagen se asigna a otra, los datos de la imagen no se copian, y ambas imágenes apuntarán al mismo bloque de memoria". "Se mantiene un recuento de referencias tal que la memoria se liberará solo cuando se destruyan todas las referencias a la imagen. Si desea crear una imagen que contendrá una nueva copia de la imagen original, usará el método copyTo(). " - de "OpenCV 2 Computer Vision Application Programming Cookbook" (p.28). – Alexey

+1

aún no necesita el nuevo en ese caso, la asignación de la nueva imagen en la pila también funciona. Pero, ¿no es esta una característica que desea, la copia compartida en su memoria intermedia circular? –

2

Su implementación es similar a la que muestra este blogger. Deberías leer ese blog para ver si te perdiste algo en tu implementación.

Si sus objetos Mat son caros de crear/copiar, debe evitar la creación/copia/eliminación continua. En su lugar, debe tener un grupo (también conocido como lista libre) de objetos Mat que continuamente obtienen reciclado en algún tipo de arquitectura de tubería. Describo este tipo de arquitectura en este answer a una pregunta relacionada.

En esa respuesta, sugerí usar una pila de bloqueo para implementar el conjunto, pero también podría usar su bloqueo circular_buffer. La razón por la que sugerí una pila fue porque pensé que podría ser más compatible con la memoria caché, pero en realidad nunca medí para ver si podía hacer la diferencia.

+0

Los objetos de tapete (imágenes) no son demasiado grandes y tienen más o menos el mismo tamaño durante cada llamada. Me acabo de dar cuenta de que puedo asignar objetos Mat en la pila en su lugar. – Alexey

+0

He estado utilizando grupos de objetos (basados ​​en colas de bloqueo) durante mucho tiempo. De hecho, utilizo el patrón de paso de mensajes poolObject + casi exclusivamente para mis diseños de aplicaciones multiproceso. El no-copy, no-malloc, no-GC y el control de flujo incorporado no son las únicas ventajas. En las aplicaciones de GUI, la creación de grupos de objetos antes de cualquier formulario o subproceso de trabajo significa que, en general, puedo olvidarme de la destrucción explícita del grupo o la molestia por terminación de subprocesos. Volcar los niveles de la piscina en un temporizador muestra fugas sin herramientas de filtración de terceros como V ******* que ralentiza la aplicación wole a paso de tortuga. –

+0

De forma predeterminada, el constructor de copia de cv :: Mat crea una copia superficial. – Reunanen

Cuestiones relacionadas