我们前面介绍了线程的同步与互斥中的互斥锁与条件变量,接下俩我们实现线程的同步与互斥的下一个主题:信号量
我们在进程中也学习过信号量信号量—-进程间通信,那个信号量完全可以运用在线程通信上,且信号量是以集合的形式出现,我们实现线程间的互斥所用的信号量是以个数的形式出现,而且实现要比进程间通信的信号量简单的多。
信号量的函数接口:
信号量初始化
参数:
sem表示我们定义的信号量;
pshared为0,表示信号量用于同一个进程间的线程是同步的;
value表示的是可用资源的数量
信号量的销毁
信号量的P操作
上面的三个函数都可以获得锁资源,但若信号量的值为0,sem_wait将挂起等待,sem_trywait将非阻塞等待(先去做别的事情,一段时间过后再去看是否申请到锁)
信号量的V操作
使信号量的值加1,同时唤醒等待的线程
接下来我们运用信号量来重新实现生产者—-消费者模型,前面我们学习条件变量时时实现过,但缓冲区运用的是带头单链表来实现,我们今天运用“环形队列”来作为我们的缓冲区存放数据,环形队列用数组来实现。
一个生产者—一个消费者模型
分析:
1. 生产者要先与消费者
2. 当环形队列为空,必须保证生产者先运行(为空或则满由计数器决定)
3. 当环形队列为满时,必须保证消费者先运行
生产者关系的只有环形队列中格子都的个数,即blanks,消费者
关心的是环形队列中是否有有效的数据,,即datas,,所以我们设立两个信号量。
代码:
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#define SIZE 64
int buf[SIZE];
sem_t blanks,datas;
void* producter(void* arg){
int i = 0;
while(1){
sem_wait(&blanks);
int data = rand()%1234;
buf[i] = data;
printf("produce data is:%d\n",data);
i++;
i%=SIZE;
sem_post(&datas);
// sleep(1);
}
}
void* consumer(void* arg){
int i = 0;
while(1){
sem_wait(&datas);
int data = buf[i];
printf("consumer data:%d\n",data);
i++;
i%=SIZE;
sem_post(&blanks);
sleep(1);
}
}
int main()
{
sem_init(&blanks,0,SIZE);
sem_init(&datas,0,0);
pthread_t id1,id2;
pthread_create(&id1,NULL,producter,NULL);
pthread_create(&id2,NULL,consumer,NULL);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
sem_destroy(&blanks);
sem_destroy(&datas);
}
在linux下运行图片
当生产者产生数据慢,而消费者获取数据快的结果图为
可以看出,环形队列中,消费者绝对不会超过生产者
当生产者生产数据快,而消费者获取数据慢时结果图为
有结果图可以验证出,生产者当讲环形链表生产满数据后,不会再生产,等待消费者释放空格,生产者才能再次的生产数据。