原文:https://github.com/angrave/SystemProgramming/wiki/Synchronization%2C-Part-2%3A-Counting-Semaphores
计数信号量包含一个值,并支持两个操作“等待”和“发布”。 Post 递增信号量并立即返回。如果计数为零,“等待”将等待。如果计数不为零,则信号量递减计数并立即返回。
类比是饼干罐中的饼干(或宝箱中的金币)的计数。在拿饼干之前,请拨打“等待”。如果没有剩下的 cookie,那么wait
将不会返回:它将wait
直到另一个线程通过调用 post 增加信号量。
简而言之,post
递增并立即返回,而如果计数为零,wait
将等待。在返回之前它将减少计数。
本页介绍了未命名的信号量。不幸的是 Mac OS X 还不支持这些。
首先确定初始值是零还是其他值(例如,数组中剩余空格的数量)。与 pthread 互斥锁不同,没有创建信号量的快捷方式 - 使用sem_init
#include <semaphore.h>
sem_t s;
int main() {
sem_init(&s, 0, 10); // returns -1 (=FAILED) on OS X
sem_wait(&s); // Could do this 10 times without blocking
sem_post(&s); // Announce that we've finished (and one more resource item is available; increment count)
sem_destroy(&s); // release resources of the semaphore
}
是!与互斥锁不同,增量和减量可以来自不同的线程。
是的 - 虽然信号量的开销更大。要使用信号量:
- 用一个计数器初始化信号量。
- 用
sem_wait
替换...lock
- 用
sem_post
替换...unlock
互斥量是一个信号量,它始终是waits
posts
sem_t s;
sem_init(&s, 0, 1);
sem_wait(&s);
// Critical Section
sem_post(&s);
是! sem_post
是可以在信号处理程序中正确使用的少数几个函数之一。这意味着我们可以释放一个等待线程,该线程现在可以使我们不允许在信号处理程序本身内调用的所有调用(例如printf
)。
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <semaphore.h>
#include <unistd.h>
sem_t s;
void handler(int signal)
{
sem_post(&s); /* Release the Kraken! */
}
void *singsong(void *param)
{
sem_wait(&s);
printf("I had to wait until your signal released me!\n");
}
int main()
{
int ok = sem_init(&s, 0, 0 /* Initial value of zero*/);
if (ok == -1) {
perror("Could not create unnamed semaphore");
return 1;
}
signal(SIGINT, handler); // Too simple! See note below
pthread_t tid;
pthread_create(&tid, NULL, singsong, NULL);
pthread_exit(NULL); /* Process will exit when there are no more threads */
}
注意,健壮的程序不会在多线程程序中使用signal()
(“多线程进程中的信号()的效果未指定。” - 信号手册页);一个更正确的程序需要使用sigaction
。
阅读手册页: