2011-12-18 14 views
5

Los C++ 11 define estándar unique_lock::unlock como (§ 30.4.2.2.2, p 1159.)¿unique_lock :: unlock no está especificado en el estándar C++ 11?

void unlock(); 
Effects: pm->unlock() 
Postcondition: owns == false 
Throws: system_error when an exception is required (30.2.2). 
Error conditions: 
    — operation_not_permitted — if on entry owns is false. 

Todas las demás operaciones de bloqueo especifican que se produce una excepción en al menos dos ocasiones:

  • El mutex es NULL (lanza system_error con errc::operation_not_permitted)
  • El mutex ya está bloqueado (lanza system_error con errc::operation_not_permitted)

El problema con el mutex no válido es obviamente posible para unlock, sin embargo, el estándar especifica el comportamiento del programa solo para los problemas de bloqueo. ¿Es un error real en el estándar o me falta algo?

+0

No estoy seguro de seguir. ¿Por qué es "obviamente posible" que se llame a 'desbloquear' cuando el mutex no es válido? Puede inferir que como el efecto de 'unlock()' es 'pm-> unlock()', para evitar el comportamiento indefinido 'pm' no debe ser nulo y debe cumplirse el contrato del' BasicLockable' '* pm' , por lo que el bloqueo debe ser propiedad del agente de ejecución actual. ¿Hay alguna sutileza que me estoy perdiendo? –

Respuesta

7

Aunque no se indica explícitamente, unique_lock tiene las siguientes invariantes:

if pm == nullptr then owns == false 
if owns == true then pm != nullptr 

simplemente no hay manera de conseguir el unique_lock en un estado que infringe estas invariantes, excepto a través de un comportamiento no definido. Así que la cláusula:

— operation_not_permitted — if on entry owns is false. 

cubre el caso de que pm == nullptr.

Tenga en cuenta que ~unique_lock() solo llama a pm->unlock() si owns es verdadero. Si owns es verdadero, entonces pm != nullptr y por lo tanto unlock() no se puede tirar.

0

pm es el mutex_type y la definición de desbloqueo en std::mutex es:

void unlock() noexcept; 

Es decir, la función unlock no puede lanzar excepciones, por lo tanto, no tiene unique_lock::unlock para heredar cualquiera de esas excepciones. En cuanto a por qué puede lanzar cualquier excepción en absoluto es un misterio.

Es un poco molesto que el destructor para unique_lock pueda lanzar una excepción (ya que supongo que tendrá que llamar al unlock donde también puede). Esto me parece malo, ya que utilizar un objeto de bloqueo para desbloquearlo correctamente durante el manejo de excepciones es una expresión muy común. Es realmente malo que la cerradura pueda emitir una excepción durante el desenrollado de la pila, especialmente porque no se permite el mutex subyacente.

Algo definitivamente está mal aquí.

Todavía estoy trabajando desde el último borrador público, tal vez esto se fijó

+0

Estoy mirando el estándar real C++ 11. Ni 'unique_ptr :: ~ unique_ptr' es' noexcept', ni se ha implementado la propuesta de agregar implícitamente noexcept para destructores, por lo que no se ha corregido.Sin embargo, creo que este es un problema diferente. El estándar no especifica qué sucede en el caso, cuando 'unique_ptr' no tiene un mutex asociado y se llama a 'unlock' en ese bloqueo. –

Cuestiones relacionadas