¿Cómo funciona esta implementación de semáforo?

¡Feliz Navidad!

Estoy leyendo El Pequeño Libro de los Semáforos . Hay una implementación de semáforos en C en el libro que no entiendo completamente. Vea a continuación el código. Hay esta variable de despertadores . El autor explica:

las activaciones cuentan el número de señales pendientes; es decir, el número de subprocesos que se han despertado pero aún no se han reanudado la ejecución. El motivo de las activaciones es asegurarse de que nuestros semáforos tengan la Propiedad 3, que se describe en la Sección 4.3.

y

Propiedad 3: si hay subprocesos esperando en un semáforo cuando un subproceso ejecuta la señal, entonces uno de los subprocesos en espera debe ser activado.

Ok, creo que entiendo el significado de la propiedad. Uno de los hilos en espera debe obtener el mutex y no otro (por ejemplo, los hilos de señalización). Corríjame si me equivoco. Lo que no entiendo es cómo se garantiza esta propiedad con este mecanismo. Yo diría que la propiedad no está garantizada. Todavía es posible que un proceso de no espera obtenga el mutex. ¿Qué me estoy perdiendo?

typedef struct { int value, wakeups; Mutex *mutex; Cond *cond; } Semaphore; // SEMAPHORE Semaphore *make_semaphore (int value) { Semaphore *semaphore = check_malloc (sizeof(Semaphore)); semaphore->value = value; semaphore->wakeups = 0; semaphore->mutex = make_mutex (); semaphore->cond = make_cond (); return semaphore; } void sem_wait (Semaphore *semaphore) { mutex_lock (semaphore->mutex); semaphore->value--; if (semaphore->value cond, semaphore->mutex); } while (semaphore->wakeups wakeups--; } mutex_unlock (semaphore->mutex); } void sem_signal (Semaphore *semaphore) { mutex_lock (semaphore->mutex); semaphore->value++; if (semaphore->value wakeups++; cond_signal (semaphore->cond); } mutex_unlock (semaphore->mutex); } 

El miembro de wakeups no pretende proteger al mutex de ser adquirido por algo que no sea un hilo en espera, sino por evitar que se liberen demasiados hilos desde la función sem_wait() .

La pthread_cond_signal() función pthread_cond_signal() que cond_signal() envuelve tiene las siguientes declaraciones en su documentación (énfasis agregado):

La función pthread_cond_signal() desbloqueará al menos uno de los subprocesos que están bloqueados en la variable de condición especificada cond (si alguno de los subprocesos está bloqueado en cond ).

Y:

En un multiprocesador, puede ser imposible que una implementación de pthread_cond_signal() evite el deslocking de más de un subproceso bloqueado en una variable de condición.

Entonces, como ejemplo, es posible que cuando hay 3 subprocesos esperando la condición, que se liberen dos (o los tres) cuando se realiza la llamada cond_signal() . El contador de wakeups garantiza que solo el número apropiado de subprocesos realmente salga de la función sem_wait() . Los otros permanecerán en el bucle do / while y esperarán la condición nuevamente.

Lo que significa esta propiedad es que el subproceso de señalización debe liberar la CPU en nombre de uno de los subprocesos en espera, si hay alguno. pthread_cond_signal () garantiza exactamente esto y por el mismo motivo.

La función pthread_cond_signal () desbloqueará al menos uno de los subprocesos que están bloqueados en la variable de condición especificada cond (si alguno de los subprocesos está bloqueado en cond).