- 信号量是一种临界资源,它的本质是计数器。
- 信号量的基本操作有两种:P操作和V操作。P操作相当于给计数器减一,V操作相当于给计数器加一。
- 信号量描述了其所要保护的临界资源的数目。因为信号量本身也是一种临界资源,所以我们用它去保护其他临界资源的前提是要保证信号量自身操作的原子性。
- POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源的目的。单POSIX可以用于线程间同步。
- 信号量P操作成功,表示允许访问临界资源。
有关信号量的常见函数:
1、初始化信号量
函数原型:int sem_init(sem_t *sem,int pshared,unsigned int value);
参数:
pshared:0表示线程间共享,非零表示进程间共享。
value:信号量初始值
2、销毁信号量
函数原型:int sem_destroy(sem_t *sem);
3、等待信号量
函数原型:int sem_wait(sem_t *sem);
功能:等待信号量,会将信号量的值减一,相当于对信号量进行P操作。
4、发布信号量
函数原型:int sem_post(sem_t *sem);
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量的值加一,相当于对信号量进行V操作。
- 生产者-消费者的例子是基于链表的,其空间可以动态分配,现在基于固定大小的环形队列重写这个程序(POSIX信号量):
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#define M 6
int ring[M];
sem_t semBlank,semData;
void* runC(void *arg){
int i = 0;
int d;
while(1){
sem_wait(&semData);
d = ring[i];
i++;
i %= M;
printf("comsumer done , data is %d\n",d);
sem_post(&semBlank);
sleep(1);
}
}
void* runP(void* arg){
int d = 0;
int i = 0;
while(1){
sem_wait(&semBlank);
ring[i] = rand()%123+1;
d = ring[i];
i++;
i %= M;
printf("product done , data is %d\n",d);
sem_post(&semData);
}
}
int main(){
sem_init(&semBlank,0,M);
sem_init(&semData,0,0);
srand((unsigned long)time(NULL));
pthread_t t1,t2;
pthread_create(&t1,NULL,runC,NULL);
pthread_create(&t2,NULL,runP,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
sem_destroy(&semBlank);
sem_destroy(&semData);
}
结果演示:
通过结果我们可以看出,生产者先生产一些数据,等到生产者生产的数据占满整个环形队列时,生产者就停止生产,直到有消费者拿走数据。此时消费者拿走一条数据,生产者就生产一条数据。