2010-05-01 9 views
6

biblioteca hilo C++ 0x o Boost.thread definen no miembro función de plantilla variadic que bloquear todos bloqueo evitando el bloqueo de muertos.¿Por qué no hay bloqueos de ámbito para múltiples mutexes en C++ 0x o Boost.Thread?

template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...); 

Si bien esta función ayuda a evitar a punto muerto, la norma no incluye el bloqueo de ámbito asociado a escribir el código de seguridad es una excepción.

{ 
    std::lock(l1,l2); 
    // do some thing 
    // unlock li l2 exception safe 
} 

Eso significa que tenemos que utilizar otro mecanismo como el bloque try-catch para hacer que el código de seguridad excepción o definir nuestra propia cerradura con ámbito en varios mutex nosotros mismos o incluso hacer que

{ 
    std::lock(l1,l2); 
    std::unique_lock lk1(l1, std::adopted); 
    std::unique_lock lk2(l2, std::adopted); 
    // do some thing 
    // unlock li l2 on destruction of lk1 lk2 
} 

Por qué la norma no incluye una cerradura restringidos en múltiples mutexes del mismo tipo, como por ejemplo

{ 
    std::array_unique_lock<std::mutex> lk(l1,l2); 
    // do some thing 
    // unlock l1 l2 on destruction of lk 
} 

o tuplas de mutexes

{ 
    std::tuple_unique_lock<std::mutex, std::recursive_mutex> lk(l1,l2); 
    // do some thing 
    // unlock l1 l2 on destruction of lk 
} 

¿hay algo malo en el diseño?


Actualizado: Descripción de la norma

template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...); 

Requiere: Cada tipo de parámetro de plantilla deberán cumplir los requisitos mutex, excepto que una llamada a try_- bloqueo() puede lanzar una excepción . [Nota: la plantilla de la clase unique_lock cumple estos requisitos cuando se crea una instancia adecuada. -finalizar]

Efectos: Todos los argumentos se bloquean mediante una secuencia de llamadas a lock(), try_lock() o unlock() en cada argumento. La secuencia de llamadas no dará como resultado un interbloqueo, pero de lo contrario no se especificará. [Nota: se debe usar un algoritmo de evitación de interbloqueo, como try-and-back-off, pero el algoritmo específico no se especifica para evitar implementaciones que restringen excesivamente. nota -fin] Si una llamada para bloquear() o try_lock() lanza una excepción, desbloquear() será llamada para cualquier argumento de que había sido bloqueado por una llamada para bloquear() o try_lock().


Acepto la respuesta. Entiendo que la razón principal es porque no hay tiempo suficiente para mejorar la biblioteca de Threads C++ 0x. Espero que TR2 incluya muchas más cosas.

+1

Buena pregunta, no veo por qué no hay un 'scoped_multi_lock (T ...)'. –

+1

De hecho, me parece que las funciones 'lock (...)' están desequilibradas. Por lo menos, también esperaría un 'desbloqueo (...)' equivalente. Sin embargo, parece que el mejor lugar para agregar dicha funcionalidad sería a la clase 'lock_guard'. Donde podría construirse con múltiples bloqueables y desbloquearlos luego de la destrucción. A diferencia de muchas otras clases de plantillas. – GrafikRobot

+0

@Grafik Tienes razón. desbloquear también debe estar en el estándar. La diferencia es que el desbloqueo (...) no puede empatar. –

Respuesta

3

creo que al proporcionar defer_lock_t (y adopt_lock_t) la expectativa es que el uso será como el segundo ejemplo, o probablemente más como:

std::unqiue_lock ul1(l1, std::deferred); 
std::unique_lock ul2(l2, std::deferred); 
std::lock(ul1, ul2); 

Esto es seguro excepción y todas esas cosas buenas.

Desde luego, no puedo pretender conocer la mente de los diseñadores, pero mi conjetura es que están haciendo un esfuerzo para proporcionar un conjunto mínimo de portátiles, caja fuerte, primitivas.Un tipo de cerradura con múltiples focos es solo una guinda, y es la guinda si se debe especificar y diseñar en el estándar, o en bobina de refuerzo. La formación de hielo debe implementarse (y por supuesto, el estándar debe preocuparse por implementación también, mira lo que sucedió con la exportación).

+0

'exportar' es una categoría completamente diferente y (habría) requerido importantes cambios arquitectónicos en los compiladores. ¿Por qué crees que necesita tanto hielo? Debe ser solo de una sola escritura en términos de las primitivas ya dadas. –

+0

@Logan Disculpa que use el error adoptado en lugar de adop_lock. –

+0

@gf, esa es mi opinión. Escribe _ una vez en términos de las primitivas ya dadas, que es lo que lo convierte en formación de hielo, por lo que no necesita estar en la norma o ser una carga para los implementadores. –

-1

La construcción de un objeto que encierra múltiples cerraduras no evitar los puntos muertos más de lo que el bloqueo de forma individual. No puede bloquear dos bloqueos simultáneamente ... a menos que use dos hilos, lo que hace que el punto sea derrotado. Esto es cierto incluso si los pones en la misma declaración.

+3

Consulte el estándar. Utiliza un algoritmo que usa try_lock y desbloqueo que ayuda a evitar interbloqueo, en los casos en que dos subprocesos toman ambos registros utilizando la misma función. –

+0

¿Cómo es eso diferente al OP simplemente encerrándolos solo? Podría ser que malinterpreté la pregunta, pero pensé que estaba sugiriendo que al tener una estructura de bloqueo múltiple, obviamente evitaría bloqueos instantáneos en lugar de bloquearlos uno tras otro. – Puppy

+0

No, se trataba de seguridad de excepción y estilo múltiple de bloqueos RAII. Lea la documentación de Boost.Thread o el borrador de C++ 0x sobre 'lock()'. –

Cuestiones relacionadas