一、信号量 Semaphore :  不是锁,大部分同步  

     二元信号量:互斥锁

     以信号量集 进行创建,统计某种资源个数 --- 计数器 --- 本身: 临界资源

     信号量,和Mutex不同的是这个数量可以大于1。即,如果信号量描述的资源数目是1时,此时的信号量和互斥锁相同!

     semaphore变量的类型为sem_t。在用完semaphore变量之后应该调用sem_destroy()释放与semaphore相关的资源。

#include <semaphore.h>           Link with -lrt or -pthread.

int sem_init(sem_t *sem, int pshared, unsigned int value);//初始化一个semaphore变量

  //value参数:表示可用资源的数量;  pshared参数:0--> 信号量用于同一进程的线程间 同步

int sem_wait(sem_t *sem); //相当于P操作,信号量-1  阻塞进程 

int sem_trywait(sem_t *sem);//相当于P操作,信号量-1   立即返回

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

int sem_post (sem_t* sem);//相当于V操作,信号量+1,同时发出唤醒的信号给等待的进程/线程。

int sem_destroy (sem_t* sem);//销毁 信号量


二、环形缓冲区:判断环形buffer为满---> 使用计数器,格子数为0

    两个信号量:buffer中格子数-->sem_blank(初始化为_SIZE_);

                buffer中数据-->sem_data(初始化 0)。

    wKioL1cccjvxbEqnAAAUZZ0fhME515.png

三、生产者-消费者模型

1、单生产者-消费者模型:

#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>

#define _SIZE_ 20  //定义环形buffer
sem_t blank;
sem_t data;
int buffer[_SIZE_];

void *product(void *arg)
{
	int index=0,count=0;
	while(1)
	{
		sem_wait(&blank);//p
		buffer[index]=count++;
		sleep(1);
		sem_post(&data);//v
		index++;
		index%=_SIZE_;
	}
}
void *consumer(void *arg)
{
	int index=0,count=0;
	while(1)
	{
		sem_wait(&data);//p
		count=buffer[index];
		printf("consumer data done:%d\n",count);
		sem_post(&blank);//v
		index++;
		index%=_SIZE_;
	}
}

int main()
{
	sem_init(&blank,0,_SIZE_);
	sem_init(&data,0,0);
	pthread_t tid1,tid2;
	pthread_create(&tid1,NULL,product,NULL);
	pthread_create(&tid2,NULL,consumer,NULL);
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	sem_destroy(&blank);
	sem_destroy(&data);
	return 0;
}

运行结果:

    wKiom1ccbd2zOb3CAABUWwdamr4167.jpg

        ... ...

2、多生产者-消费者模型:

// 其他代码见上
int main()
{
	sem_init(&blank,0,_SIZE_);
	sem_init(&data,0,0);
	pthread_t tid1,tid2,tid3,tid4;
	pthread_create(&tid1,NULL,product,NULL);
	pthread_create(&tid2,NULL,consumer,NULL);
	pthread_create(&tid3,NULL,product,NULL);
	pthread_create(&tid4,NULL,consumer,NULL);
	
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	pthread_join(tid3,NULL);
	pthread_join(tid4,NULL);
	sem_destroy(&blank);
	sem_destroy(&data);
	return 0;
}

运行结果:

    wKioL1ccbuji7zh2AAA9ZrJk8ls794.jpg

        ... ...

    wKioL1ccbujCwMeTAAAkDtoOp0A630.jpg

        ... ...

    wKiom1ccbiOS6EndAAAgJSnHXwo121.jpg

        ... ...

    注意:在信号量内部(生产者、消费者)需要加锁(即P、V操作)。