Ejemplo de exclusión mutua
Los subprocesos Posix definen un conjunto de funciones mutuamente excluyentes específicamente para la sincronización de subprocesos.
1. Creación y Destrucción
Hay dos formas de crear un mutex, estático y dinámico. POSIX define una macro PTHREAD_MUTEX_INITIALIZER para inicializar estáticamente un bloqueo mutex, de la siguiente manera: PTHREAD _ MUTEX _ tmutex = PTHREAD _ MUTEX _ INITIALIZER; en la implementación de LinuxThreads, pthread_mutex_t es una estructura y PTHREAD_MUTEX_INITIALIZER es una constante estructural.
El método dinámico consiste en utilizar la función pthread_mutex_init() para inicializar el mutex. La API se define de la siguiente manera: int pthread _ mutex _ init (pthread _ mutex _ t * mutex, const pthread _ mutex ttr _ t * mutex ttr), donde mutex ttr se usa para especificar el atributo de exclusión mutua (ver más abajo), si está vacío, utilice las propiedades predeterminadas.
Pthread_mutex_destroy() se utiliza para cancelar un bloqueo mutex. La API se define de la siguiente manera: int pthread _ mutex _ destroy (pthread _ mutex _ t * mutex) Destruir un bloqueo mutex significa liberar los recursos que ocupa. , y requiere que el candado esté actualmente abierto. Dado que los bloqueos mutex no ocupan ningún recurso en Linux, pthread_mutex_destroy() en LinuxThreads no tiene otras acciones excepto verificar el estado del bloqueo (el estado del bloqueo devuelve EBUSY).
2. Atributos del bloqueo mutex
Los atributos del mutex se especifican cuando se crea el bloqueo. En la implementación de LinuxThreads, solo hay un atributo de tipo bloqueo. Los diferentes tipos de bloqueo se comportan de manera diferente cuando se intenta bloquear un mutex que ya está bloqueado. Actualmente (glibc2.2.3, linuxthreads0.9) hay cuatro valores para elegir:
* PTHREAD_MUTEX_TIMED_NP, este es el valor predeterminado, que es un bloqueo normal. Cuando un subproceso se bloquea, otros subprocesos que solicitan el bloqueo formarán una cola de espera y obtendrán el bloqueo según la prioridad después del desbloqueo. Esta estrategia de bloqueo garantiza la equidad en la asignación de recursos.
* PTHREAD_MUTEX_RECURSIVE_NP, bloqueo anidado, permite que el mismo hilo adquiera con éxito el mismo bloqueo varias veces y lo desbloquee mediante múltiples desbloqueos. Si lo solicita un hilo diferente, competirá nuevamente cuando se desbloquee el hilo bloqueado.
* PTHREAD_MUTEX_ERRORCHECK_NP, bloqueo de verificación de error, si el mismo hilo solicita el mismo bloqueo, devuelve EDEADLK; de lo contrario, la misma acción que el tipo PTHREAD_MUTEX_TIMED_NP. Esto garantiza que en el caso más simple, cuando no se permiten múltiples bloqueos, no pueda ocurrir ningún punto muerto.
* PTHREAD_MUTEX_ADAPTIVE_NP, bloqueo adaptativo, el tipo de bloqueo más simple, solo espera a que se desbloquee antes de competir.
3. Operación de bloqueo
La operación de bloqueo incluye principalmente bloquear pthread_mutex_lock(), desbloquear pthread_mutex_unlock() y probar el bloqueo pthread_mutex_trylock(). No importa qué tipo de bloqueo sea, dos subprocesos diferentes no pueden obtenerlo al mismo tiempo y deben esperar a que se desbloquee. Para bloqueos ordinarios y tipos de bloqueos adaptativos, el desbloqueo puede ser cualquier subproceso en el mismo proceso; el bloqueo de detección de errores debe ser desbloqueado por el bloqueo para que sea válido; de lo contrario, se devolverá EPERM para bloqueos anidados, la documentación y los requisitos de implementación deben ser; desbloqueado por la cerradura del gabinete, pero los resultados experimentales no mostraron tal restricción y la discrepancia no fue explicada. Si un subproceso en el mismo proceso no se desbloquea después del bloqueo, ningún otro subproceso podrá obtener el bloqueo.
int pthread _ mutex _ lock(pthread _ mutex _ t * mutex)
int pthread _ mutex _ unlock(pthread _ mutex _ t * mutex)
int pthread _ mutex _ try lock(pthread _ mutex _ t * mutex)
La semántica de pthread_mutex_trylock() es similar a pthread_mutex_lock(), excepto que cuando el bloqueo está ocupado, devuelve EBUSY en lugar de espera.
4. Otros
El mecanismo de bloqueo de subprocesos POSIX implementado por Linux no es un punto de cancelación, por lo que un subproceso del tipo de cancelación retrasada no abandonará el bloqueo y esperará porque recibe una señal de cancelación. . Vale la pena señalar que si el hilo se cancela después de bloquearlo y antes de desbloquearlo, el bloqueo permanecerá bloqueado para siempre. Por lo tanto, si hay un punto de cancelación en una sección crítica o se establece un tipo de cancelación asíncrona, se debe desbloquear en la función de devolución de llamada de salida.
Al mismo tiempo, este mecanismo de bloqueo no es seguro para señales asincrónicas, es decir, los bloqueos mutex no deben usarse en el procesamiento de señales, de lo contrario conducirá fácilmente a un punto muerto.
El atributo de bloqueo mutex utiliza un bloqueo mutex (Mutex) para permitir que los subprocesos se ejecuten en orden. En términos generales, los mutex sincronizan varios subprocesos garantizando que solo un subproceso ejecute partes críticas de código a la vez. Los mutex también pueden proteger código de un solo subproceso.
Para cambiar las propiedades mutuamente excluyentes predeterminadas, puede declarar e inicializar el objeto de propiedad. Normalmente, las propiedades mutuamente excluyentes se establecen en algún lugar al principio de la aplicación para que puedan encontrarse rápidamente y modificarse fácilmente. La tabla 4-1 enumera las funciones para manejar propiedades mutuamente excluyentes.
Tabla 4-1 Operaciones de rutina de atributo mutex Descripción de la función relacionada Inicializar el objeto de atributo mutex pthread_mutexattr_init Sintaxis Destruir el objeto de atributo mutex pthread_mutexattr_destroy Sintaxis Establecer el rango de mutex pthread _ mutexattr _ init Sintaxis compartida Obtener el rango de mutex pthread _ mutextert _ la sintaxis getpsared establece el atributo de tipo mutex pthread _ mutextert _ la sintaxis settype obtiene el atributo de tipo mutex pthread _ mutextert _ la sintaxis gettype establece el protocolo de atributo mutex pthread _ m Utexattr_setprotocol atributo mutex pthread _ mutextettr _ setprioceling sintaxis para obtener el mutex El límite superior. de la prioridad del atributo exclusivo pthread_mutex. La sintaxis attr_getprioceiling establece el límite de prioridad superior de un mutex. Pthread_mutex_setLa sintaxis de prioridad obtiene el límite superior de la prioridad del mutex. La sintaxis Pthread_mutex_getPrioritizing establece las propiedades de robustez de un mutex. pthread_mutexattr_setro_setro. La sintaxis de Bust_np obtiene el atributo robusto de un Mutex pthread_mutexattr_getrobust_np Sintaxis La tabla 4–2 muestra las diferencias entre los subprocesos de Solaris y los subprocesos POSIX al definir alcances de mutex.
tabla 4–2 Comparación del rango Mutex Solaris POSIX define USync _ Processpthread _ Process _ Shared, que se utiliza para sincronizar subprocesos en este proceso y otros procesos. USYNC_PROCESS_ROBUST no tiene un equivalente POSIX para sincronizar de manera confiable subprocesos entre procesos. USync_thread thread_process_private solo se usa para sincronizar subprocesos en el proceso.