Estou tentando entender a semântica dos semáforos.
Aqui está um código:
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
sem_t sem;
void *helper(void *arg) {
sem_wait(&sem);
printf("helper woke up\n");
return NULL;
}
int main() {
sem_init(&sem, 0, 0);
pthread_t tid;
pthread_create(&tid, NULL, helper, NULL);
sleep(1);
sem_post(&sem);
sem_wait(&sem);
printf("main woke up\n");
exit(0);
}
Aqui main cria um thread auxiliar, dorme por um segundo para ter (quase) certeza de que o auxiliar executou e esperou no semáforo e então tenta postar e esperar no semáforo em rápida sucessão. De acordo com POSIX ( https://pubs.opengroup.org/onlinepubs/009695399/functions/sem_post.html ):
Se o valor do semáforo resultante desta operação for zero, então um dos threads bloqueados aguardando o semáforo poderá retornar com sucesso de sua chamada para
sem_wait()
.
Então, eu esperaria que "ajudante acordou" fosse impresso. No entanto, se você realmente executar esse código no Linux, normalmente será observado "main wake up", o que significa que, por padrão, os semáforos no Linux não podem ser justos.
Minha pergunta é: por que esse comportamento é permitido? Sim, você pode dizer "é mais fácil de implementar", mas isso não explica por que os semáforos foram projetados com essa semântica específica.
Em outro lugar, ( https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Semaphore.html ) diz que esse comportamento é preferível em algumas situações. Em que situação seria preferível um semáforo não justo? Eu apreciaria qualquer fonte detalhada sobre este tópico.
Editar: por favor, não faça do sono (1) o foco da postagem. Suponha que o thread auxiliar aguarde no semáforo (como quase sempre faz) da maneira que você desejar (rendimento, barreira, sem cronômetro, qualquer que seja). Estou interessado na semântica do semáforo aqui.