版权声明: https://blog.csdn.net/dashoumeixi/article/details/84668720
有名信号量: 文件在 /dev/shm
单消费单生产 的情况. 把sem_open 改为 sem_init 就是基于内存的信号量
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <pthread.h>
#define NBUFF 10
#define SEM_MUTEX "/semmutex"
#define SEM_NSTORED "/semnstored"
#define SEM_NEMPTY "/semnempty"
int nitems;
struct {
int buf[NBUFF];
sem_t *mutex,*nstored,*nempty; //mutex 在这个例子没必要.只是为了扩展起见
}share;
static void * producer(void * p)
{
for(int i = 0 ; i < nitems; ++i){
sem_wait(share.nempty);
sem_wait(share.mutex);
share.buf[i%NBUFF] = i;
sem_post(share.mutex);
sem_post(share.nstored);
}
return 0;
}
static void * consumer(void * p)
{
for(int i =0 ; i < nitems;++i){
sem_wait(share.nstored);
sem_wait(share.mutex);
printf("consumer : %d\n" , share.buf[i]);
sem_post(share.mutex);
sem_post(share.nempty);
}
return 0;
}
int main(int agrc, char**argv)
{
if( agrc < 2){
puts("nitems?");
return 0;
}
nitems = atoi(argv[1]);
int flag = O_CREAT;
mode_t mode = 0644;
share.mutex = sem_open(SEM_MUTEX,flag,mode,1);
// 消费者 一开始初始化 0
share.nstored = sem_open(SEM_NSTORED,flag,mode,0);
// 生产一开始初始化可连续进入 NBUFF次
share.nempty = sem_open(SEM_NEMPTY,flag,mode,NBUFF);
pthread_t tid_p , tid_c;
pthread_create(&tid_p,NULL,producer,NULL);
pthread_create(&tid_c,NULL,consumer,NULL);
pthread_join(tid_p,NULL);
pthread_join(tid_c,NULL);
int emptyvalue , storevalue ;
sem_getvalue(share.nempty,&emptyvalue);
sem_getvalue(share.nstored,&storevalue);
printf("nempty:%d, nstored:%d\n" , emptyvalue,storevalue);
return 0;
}
多个生产者 单个消费:
需要注意的是多个生产者线程 退出时 还需要通知其他的生产者线程退出,否则将死锁.
比如在下面例子中 总共生产20个数据. 启动50个消费者线程. 则只有20个线程能正常退出,其他30个线程将一直等待;
又或者你能确定只有一个生产者,但这样又失去了多生产者的意义了
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <pthread.h>
#define NBUFF 10
#define MAXTHREADS 50
int nitems , nproducers;
struct {
int buf[NBUFF];
sem_t mutex,nstored,nempty;
int nindex; //用于记录生产者生产到哪
}share;
static void * producer(void * p)
{
int i = 0;
while(1){
sem_wait(&share.nempty);
sem_wait(&share.mutex);
if(share.nindex >= nitems){ //生产完成,线程退出
//注意!! 多个生产线程,要让剩余的线程退出.否则死锁
sem_post(&share.mutex);
sem_post(&share.nempty); //如果不知道为什么,可以注释这行看看情况
break;
}
share.buf[i%NBUFF] = i++;
share.nindex++;
sem_post(&share.mutex);
sem_post(&share.nstored);
}
return 0;
}
static void * consumer(void * p)
{
for(int i =0 ; i < nitems;++i){
sem_wait(&share.nstored);
sem_wait(&share.mutex);
printf("index:%d , consumer : %d\n" , i,share.buf[i%NBUFF]);
sem_post(&share.mutex);
sem_post(&share.nempty);
}
return 0;
}
int main(int agrc, char**argv)
{
if( agrc < 2){
puts("nitems producers");
return 0;
}
nitems = atoi(argv[1]);
nproducers = atoi(argv[2]) ;
if(nproducers > MAXTHREADS)
nproducers = MAXTHREADS;
int flag = O_CREAT;
mode_t mode = 0644;
sem_init(&share.mutex,0,1);
sem_init(&share.nempty,0,NBUFF);
sem_init(&share.nstored,0,0);
pthread_t tid_p[MAXTHREADS] , tid_c;
for(int i = 0; i < nproducers ; ++i)
pthread_create(tid_p+i,NULL,producer,NULL);
pthread_create(&tid_c,NULL,consumer,NULL);
for(int i = 0 ; i< nproducers; ++i)
pthread_join(tid_p[i],NULL);
pthread_join(tid_c,NULL);
int emptyvalue , storevalue ;
sem_getvalue(&share.nempty,&emptyvalue);
sem_getvalue(&share.nstored,&storevalue);
printf("nempty:%d, nstored:%d\n" , emptyvalue,storevalue);
return 0;
}
多生产多消费:
需要注意的是:
1.在生产者线程退出时要通知一下消费者线程,否则消费者将一直等待,无法退出线程
2.在消费者中还需要添加自行退出线程的代码, 就像多生产者一样, 否则消费者线程将无法全部退出,
除非你能确定,消费者只有一个 或者 生产者的数量一定大于消费者 ,但这样的消费者代码不好,有太多的限制了;
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <pthread.h>
#define NBUFF 10
#define MAXTHREADS 50
int nitems , nproducers , nconsumers;
struct {
int buf[NBUFF];
sem_t mutex,nstored,nempty;
int index_producer;
int index_consumer;
}share;
static void * producer(void * p)
{
int i = 0;
while(1){
sem_wait(&share.nempty);
sem_wait(&share.mutex);
if(share.index_producer >= nitems){
sem_post(&share.mutex);
sem_post(&share.nempty);
/*
需要注意.一定要通知消费者,否则消费者死锁
比如5个线程全部生产完毕. 此时消费并不知道.还在sem_wait等待
*/
sem_post(&share.nstored);
break;
}
share.buf[i%NBUFF] = i++;
share.index_producer++;
sem_post(&share.mutex);
sem_post(&share.nstored);
}
return 0;
}
static void * consumer(void * p)
{
while(1){
sem_wait(&share.nstored);
sem_wait(&share.mutex);
if(share.index_consumer >= nitems){ //多消费者的情况,需要判断是否已经完成消费
/*
当生产者通知结束后.由于当前是多消费者的情况.
所以必须加上这2行代码,除非你能确定, 只有一个消费者或者
生产者一定是大于消费者的
*/
sem_post(&share.nstored); //自行退出线程
sem_post(&share.mutex);
break;
}
printf("index:%d , consumer : %d\n" , share.index_consumer,
share.buf[share.index_consumer%NBUFF]);
share.index_consumer++;
sem_post(&share.mutex);
sem_post(&share.nempty);
}
return 0;
}
int main(int agrc, char**argv)
{
if( agrc < 3){
puts("nitems producers consumers");
return 0;
}
nitems = atoi(argv[1]);
nproducers = atoi(argv[2]) ;
nconsumers = atoi(argv[3]);
if(nproducers > MAXTHREADS)
nproducers = MAXTHREADS;
if(nconsumers > MAXTHREADS)
nconsumers = MAXTHREADS;
int flag = O_CREAT;
mode_t mode = 0644;
sem_init(&share.mutex,0,1);
sem_init(&share.nempty,0,NBUFF);
sem_init(&share.nstored,0,0);
pthread_t tid_p[MAXTHREADS] , tid_c[MAXTHREADS];
for(int i = 0; i < nproducers ; ++i)
pthread_create(tid_p+i,NULL,producer,NULL);
for(int i = 0; i < nconsumers ; ++i)
pthread_create(tid_c+i,NULL,consumer,NULL);
for(int i = 0 ; i< nproducers; ++i)
pthread_join(tid_p[i],NULL);
for(int i =0 ; i < nconsumers ; ++i)
pthread_join(tid_c[i],NULL);
int emptyvalue , storevalue ;
sem_getvalue(&share.nempty,&emptyvalue);
sem_getvalue(&share.nstored,&storevalue);
printf("nempty:%d, nstored:%d\n" , emptyvalue,storevalue);
return 0;
}