信号量是一个有整数值的对象,它的语义针对某个特定的资源,它的值是可用的资源个数的抽象。
当值大于零时,值表示可用的资源个数。
当值小于零时,值表示正在等待的线程个数。
当值等于零时,表示没有线程等待,但是自己无法使用该资源。
信号量的底层是利用锁与条件变量实现的,而锁与条件变量的实现又是利用到了底层硬件的支持,包括同步原语,等待队列,休眠机制等
操作系统并发性(二):锁
操作系统并发性(三):条件变量
信号量最大的好处就是代码量小,尤其是比条件变量小的多,使用极其方便。
//头文件 #include//数据结构 sem_t s; //初始化,第三个参数表明s的初始值,第二个参数一般设置为0, //表示信号量是多个线程共享的。 sem_init(&s, 0, 1); //使用 sem_post(&s); sem_wait(&s);
sem_wait执行步骤:
- 将信号量的值减1如果此时信号量的值大于等于0,跳出,否则陷入休眠
sem_post执行步骤:
- 将信号量的值加1如果有其他线程休眠,唤醒一个线程
sem_t s; sem_init(&s, 0, 1); sem_wait(&s); //临界区代码 sem_post(&s);
使用一目了然,注意这里信号量的初值赋为1。表示第一个线程可以进入临界区。
用信号量实现条件变量以父线程等待子线程执行完毕为例。
sem_t s;
void* thr_son(void*)
{
printf("son beginn");
printf("son endn");
sem_post(&s);
return NULL;
}
int main()
{
sem_init(&s, 0, 0);
printf("father beginn");
pthread_t son;
pthread_create(&son, NULL, thr_son, NULL);
sem_wait(&s);
printf("father endn");
}
使用锁与条件变量实现信号量
这里我们用锁与条件变量实现一个自己的信号量 zem_t。
依次实现信号量的三个API,并用它实现父线程等待子线程的功能。
#include#include #include typedef struct zem_t{ int value; pthread_mutex_t mutex; pthread_cond_t cond; }zem_t; zem_t z; void zem_init(zem_t* zem_p, int value) { zem_p->value = value; pthread_mutex_init(&zem_p->mutex, NULL); pthread_cond_init(&zem_p->cond, NULL); } void zem_post(zem_t* zem_p) { pthread_mutex_lock(&zem_p->mutex); zem_p->value++; pthread_cond_signal(&zem_p->cond); pthread_mutex_unlock(&zem_p->mutex); } void zem_wait(zem_t* zem_p) { pthread_mutex_lock(&zem_p->mutex); zem_p->value--; while (zem_p->value < 0) pthread_cond_wait(&zem_p->cond, &zem_p->mutex); pthread_mutex_unlock(&zem_p->mutex); } void* thr_son(void*) { printf("son beginn"); printf("son endn"); zem_post(&z); return NULL; } int main() { zem_init(&z, 0); printf("father beginn"); pthread_t son; pthread_create(&son, NULL, thr_son, NULL); zem_wait(&z); printf("father endn"); }



