threading thread method lock ejemplo multithreading mutex

multithreading - thread - sync lock c#



Si desbloquea un mutex ya desbloqueado, ¿el comportamiento es indefinido? (6)

Si desbloquea un mutex ya desbloqueado, ¿es inseguro, seguro o indefinido el comportamiento?

El propósito de la pregunta está relacionado con el siguiente código, donde no sé si sería mejor desbloquear los mutex dentro del bloque if, o simplemente fuera del bloque if.

// This chunk of code makes dual locking semi-autonomous. int c_lckd = 0, q_lckd = 0; if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1; if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1; if (q_lckd && !c_lckd) { QUEUE_UNLOCK; q_lckd = 0; } else if (c_lckd && !q_lckd) { CRUNCH_UNLOCK; c_lckd = 0; } if (c_lckd && q_lckd) { printf("cr = %d, max = %d, cnt = %d/n", crunching, max_crunching, queue_count(conn_queue)); if (crunching < max_crunching && queue_count(conn_queue)) { pthread_t tid = pthread_create( &tid, NULL, crunch_conn, (void *)queue_dequeue(conn_queue) ); crunching++; } CRUNCH_UNLOCK QUEUE_UNLOCK }

Gracias chenz


Como señaló Glen, obtienes un comportamiento indefinido si intentas pthread_mutex_unlock un mutex desbloqueado, no lo intentes. La depuración de hilos es lo suficientemente difícil como para no invocar un comportamiento indefinido también.

Más importante aún, el estilo de codificación es un poco inusual, ya que no va a hacer nada a menos que obtenga ambos bloqueos, codifique en consecuencia:

if (pthread_mutex_trylock(&crunch_mutex) == 0) { if (pthread_mutex_trylock(&queue_mutex) == 0) { printf("cr = %d, max = %d, cnt = %d/n", crunching, max_crunching, queue_count(conn_queue)); if (crunching < max_crunching && queue_count(conn_queue)) { pthread_t tid; int rc = pthread_create(&tid, NULL, crunch_conn, (void *)queue_dequeue(conn_queue)); if (rc != 0) { // Error recovery // Did you need what was returned by queue_dequeue() // to requeue it, perhaps? } else { crunching++; // Do something with tid here? } } QUEUE_UNLOCK; } CRUNCH_UNLOCK; }

Esto evita las variables ''lo hice yo''; también queda claro al instante que mientras las macros de desbloqueo hagan lo que se espera (y no hay excepciones parásitas o ajustes), los mutex que están bloqueados están desbloqueados. También evita el gasto de energía en el bloqueo de la exclusión mutua cuando no está disponible la exclusión mutua, pero es un problema menor en comparación con la claridad añadida.


En general, para preguntas como esta, la documentación es la mejor fuente de información. Diferentes mutex pueden comportarse de manera diferente, o puede haber opciones en un solo mutex que hacen que se comporte diferente (como en el caso de la adquisición recursiva de un mutex en un solo hilo).


Intentalo. Este es el código que funciona correctamente.

// Mutex is not busy if(pthread_mutex_trylock(&object->mtx) == 0) { if(pthread_mutex_unlock(&object->mtx)!=0) { perror("ERRN: pthread_mutex_unlock:"); } } // Mutex is already busy else { if(pthread_mutex_unlock(&object->mtx)!=0) { perror("ERRN: pthread_mutex_unlock:"); } }

// En este punto - hemos desbloqueado correctamente el mutex.

if(pthread_mutex_destroy(&object->mtx) != 0) { perror("ERRN: pthread_mutex_destroy:"); }


No necesitas hacerlo de esa manera. Prueba esto:

// This chunk of code makes dual locking semi-autonomous. int c_lckd = 0, q_lckd = 0; if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1; if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1; if (c_lckd && q_lckd) { printf("cr = %d, max = %d, cnt = %d/n", crunching, max_crunching, queue_count(conn_queue)); if (crunching < max_crunching && queue_count(conn_queue)) { pthread_t tid = pthread_create( &tid, NULL, crunch_conn, (void *)queue_dequeue(conn_queue) ); crunching++; } } if (q_lckd) { QUEUE_UNLOCK; q_lckd = 0; } if (c_lckd) { CRUNCH_UNLOCK; c_lckd = 0; }

Es un poco más fácil de seguir y no se arriesga a intentar desbloquear un mutex desbloqueado.


Para pthreads resultará en un comportamiento indefinido. Desde la página de manual de pthread_mutex_unlock :

Llamar a pthread_mutex_unlock () con un mutex que el subproceso que llama no tiene como resultado dará lugar a un comportamiento indefinido.

Otros mutexes tendrán su propio comportamiento. Como han dicho otros, es mejor leer el manual para cualquier mutex que esté usando.


Un desbloqueo mutex debe hacerse en un hilo solo si el mismo mutex está bloqueado anteriormente en el mismo hilo. Todos los demás casos son comportamientos indefinidos según la página del manual.

Si el tipo de exclusión mutua es PTHREAD_MUTEX_DEFAULT, intentar bloquear de forma recursiva los resultados de exclusión mutua en un comportamiento indefinido. El intento de desbloquear el mutex si no estaba bloqueado por el subproceso de llamada da como resultado un comportamiento indefinido. Intentar desbloquear el mutex si no está bloqueado da como resultado un comportamiento indefinido.