c++ multithreading c++11 vector mutex

c++ - ¿Cómo puedo usar algo como std:: vector<std:: mutex>?



multithreading c++11 (5)

Tengo un número grande, pero potencialmente variable, de objetos que se escriben simultáneamente. Quiero proteger ese acceso con mutexes. Para ese fin, pensé usar un std::vector<std::mutex> , pero esto no funciona, ya que std::mutex no tiene copia ni mueve el constructor, mientras que std::vector::resize() requiere ese.

¿Cuál es la solución recomendada para este enigma?

editar : ¿Todos los contenedores de acceso aleatorio de C ++ requieren copiar o mover constructores para cambiar el tamaño? Would std :: deque ayuda?

editar de nuevo

Primero, gracias por todos tus pensamientos. No me interesan las soluciones que eviten las muticidas y / o las muevan a los objetos (me abstengo de dar detalles / razones). Entonces, dado el problema de que quiero un número ajustable de mutices (donde se garantiza que ocurrirá el ajuste cuando no hay mutex bloqueado), entonces parece haber varias soluciones.

1 Podría usar una cantidad fija de mutices y usar una función hash para mapear desde objetos a mutices (como en la respuesta del Capitán Oblivous). Esto dará lugar a colisiones, pero el número de colisiones debería ser pequeño si el número de mutices es mucho mayor que el número de subprocesos, pero aún menor que la cantidad de objetos.

2 Podría definir una clase contenedora (como en la respuesta de ComicSansMS), por ej.

struct mutex_wrapper : std::mutex { mutex_wrapper() = default; mutex_wrapper(mutex_wrapper const&) noexcept : std::mutex() {} bool operator==(mutex_wrapper const&other) noexcept { return this==&other; } };

y use un std::vector<mutex_wrapper> .

3 Podría usar std::unique_ptr<std::mutex> para gestionar mutexes individuales (como en la respuesta de Matthias). El problema con este enfoque es que cada mutex se asigna individualmente y se desasigna en el montón. Por lo tanto, prefiero

4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );

cuando un cierto número n_mutex de mutices se asigna inicialmente. Si este número más tarde se encuentra insuficiente, simplemente

if(need_mutex > n_mutex) { mutices.reset( new std::mutex[need_mutex] ); n_mutex = need_mutex; }

Entonces, ¿cuál de estos (1,2,4) debería usar?


Puede usar std::unique_ptr<std::mutex> lugar de std::mutex . unique_ptr s son movibles.


Si la eficiencia es un problema así, supongo que solo tiene estructuras de datos muy pequeñas que cambian con mucha frecuencia. Probablemente sea mejor utilizar Atomic Compare And Swap (y otras operaciones atómicas) en lugar de usar mutexes, específicamente std::atomic_compare_exchange_strong


Si quieres crear una cierta duración:

std::vector<std::mutex> mutexes; ... size_t count = 4; std::vector<std::mutex> list(count); mutexes.swap(list);


Sugiero usar un grupo de mutex fijo. Mantenga una matriz fija de std::mutex y seleccione cuál bloquear según la dirección del objeto como lo haría con una tabla hash.

std::array<std::mutex, 32> mutexes; std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()]; m.lock();

La función hashof podría ser algo simple que cambia el valor del puntero en unos pocos bits. De esta forma, solo tiene que inicializar los mutex una vez y evitará la copia de redimensionamiento del vector.


vector requiere que los valores sean móviles, para mantener una matriz contigua de valores a medida que crece. Podría crear un vector que contenga mutex, pero no podría hacer nada que pudiera necesitar cambiar su tamaño.

Otros contenedores no tienen ese requisito; cualquiera de las [forward_]list deque o [forward_]list debería funcionar, siempre y cuando construya los mutexes en su lugar durante la construcción, o usando emplace() o resize() . Las funciones como insert() y push_back() no funcionarán.

Alternativamente, puede agregar un nivel adicional de unique_ptr indirecto y almacenar unique_ptr ; pero su comentario en otra respuesta indica que usted cree que el costo adicional de la asignación dinámica es inaceptable.