linux下多线程生产者消费者实现的一个示例

来源:互联网 发布:ubuntu mysql自启动 编辑:程序博客网 时间:2024/04/30 04:39

linux下多线程生产者消费者实现的一个示例

生产者消费者问题是一个经典的进程或线程同步互斥问题,这里给出一个linux多线程实现的一个例子。linux将线程作为一个库,并不默认链接,所以在链接的时候需要加上-lpthread或-pthread参数。
这个例子使用信号量作为同步互斥机制,在一个共享的环形存储区中,创建多个生产者线程向缓冲区中写入数据,同事创建多个消费者线程从缓冲区中读出数据,缓冲区满时生产者线程等待,缓冲区空时,消费者线程等待,同时保证了只有一个线程在读或写。可以分别指定生产者和消费者线程的数量。
具体代码如下:
/*************************************************************************> File Name: pc.c> Author: gwq> Mail: 457781132@qq.com > Created Time: 2014年11月03日 星期一 17时07分01秒 ************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <pthread.h>#include <unistd.h>#include <signal.h>#define BUFFER_SIZE10#define SEM_KEY1234//信号量Key值//定义循环缓冲队列及对其的一组操作struct circle_buf {//循环缓冲队列结构int r;//读指针int w;//写指针int buf[BUFFER_SIZE];//缓冲区};int semid;//信号量idstruct sembuf semaphore;//定义一个信号量struct circle_buf cbuf;void writecbuf(struct circle_buf *cbuf, int val)//向缓冲区写一个值{cbuf->buf[cbuf->w] = val;cbuf->w = (cbuf->w + 1) % BUFFER_SIZE;//写过后指针+1}int readcbuf(struct circle_buf *pcbuf)//从当前指针读一个值,返回value{int value = pcbuf->buf[pcbuf->r];pcbuf->buf[pcbuf->r] = -1;//读过后置-1pcbuf->r = (pcbuf->r + 1) % BUFFER_SIZE;//读过后read+1return value;}void outcbuf(struct circle_buf *pcbuf){int i = 0;printf("缓冲区各单元的值:");for (i = 0; i < BUFFER_SIZE; ++i) {printf("%d%c", pcbuf->buf[i],(i == BUFFER_SIZE - 1) ? '\n' : ' ');}}int initsembuf(void)//创建信号量集,并初始化{int sem = 0;//创建3个信号量if ((semid = semget(SEM_KEY, 3, IPC_CREAT | 0666)) >= 0) {sem = 1;//第0个信号量为mutex互斥信号量,初值为1,缓冲区互斥使用(mutex)semctl(semid, 0, SETVAL, sem);sem = BUFFER_SIZE;//第1个信号量为empty同步信号量,初值为10,当前空缓冲区数(empty)semctl(semid, 1, SETVAL, sem);sem = 0;//第2个信号量为full同步信号量,初值为0,当前慢缓冲区数(full)semctl(semid, 2, SETVAL, sem);return 1;} else {return 0;}}//对信号量的PV操作void pmutex(void){semaphore.sem_num = 0;//信号量索引为0,即第一个信号量semaphore.sem_op = -1;//减1semaphore.sem_flg = SEM_UNDO;semop(semid, &semaphore, 1);}void vmutex(void){semaphore.sem_num = 0;//信号量索引为0,即第一个信号量semaphore.sem_op = 1;//加1semaphore.sem_flg = SEM_UNDO;semop(semid, &semaphore, 1);}void pempty(void){semaphore.sem_num = 1;//信号量索引为1,即第二个信号量semaphore.sem_op = -1;//减1semaphore.sem_flg = SEM_UNDO;semop(semid, &semaphore, 1);}void vempty(void){semaphore.sem_num = 1;//信号量索引为1,即第二个信号量semaphore.sem_op = 1;//加1semaphore.sem_flg = SEM_UNDO;semop(semid, &semaphore, 1);}void pfull(void){semaphore.sem_num = 2;//信号量索引为2,即第三个信号量semaphore.sem_op = -1;//减1semaphore.sem_flg = SEM_UNDO;semop(semid, &semaphore, 1);}void vfull(void){semaphore.sem_num = 2;//信号量索引为2,即第三个信号量semaphore.sem_op = 1;//加1semaphore.sem_flg = SEM_UNDO;semop(semid, &semaphore, 1);}void sigend(int sig){semctl(semid, 3, IPC_RMID);exit(0);}void *productthread(void *arg){int val = *(int *)arg;while (1) {pempty();pmutex();writecbuf(&cbuf, val);printf("生产者%d写入缓冲区的值=%d.\n", val, val);outcbuf(&cbuf);vmutex();vfull();//sleep(1);}return NULL;}void *consumerthread(void *arg){int cid = *(int *)arg;int val = 0;while (1) {pfull();pmutex();val = readcbuf(&cbuf);printf("消费者%d取走的产品的值=%d.\n", cid, val);outcbuf(&cbuf);vmutex();vempty();//sleep(1);}return NULL;}int main(int argc, char *argv[]){//初始化信号量集while (!initsembuf()) {;}//收到信号结束程序signal(SIGINT, sigend);signal(SIGTERM, sigend);int i = 0;int ret = 0;//初始化生产者消费者数量int consnum = 0;int prodnum = 0;//初始化循环缓冲队列cbuf.r = 0;cbuf.w = 0;memset(cbuf.buf, 0, BUFFER_SIZE);printf("请输入生产者进程的数目:");scanf("%d", &prodnum);int *prosarg = (int *)malloc(prodnum * sizeof(int));pthread_t *prosid = (pthread_t *)malloc(prodnum * sizeof(pthread_t));printf("请输入消费者进程的数目:");scanf("%d", &consnum);int *consarg = (int *)malloc(consnum * sizeof(int));pthread_t *consid = (pthread_t *)malloc(consnum * sizeof(pthread_t));//启动生产者for (i = 0; i < prodnum; ++i) {prosarg[i] = i + 1;ret = pthread_create(&prosid[i], NULL, productthread,(void *)&prosarg[i]);printf("消费者prosid[%d] = %lu\n", i + 1, prosid[i]);if (ret != 0) {printf("创建生产者线程失败!");exit(EXIT_FAILURE);}}for (i = 0; i < consnum; ++i) {consarg[i] = i + 1;ret = pthread_create(&consid[i], NULL, consumerthread,(void *)&consarg[i]);printf("生产者consid[%d] = %lu\n", i + 1, consid[i]);if (ret != 0) {printf("创建消费者线程失败!");exit(EXIT_FAILURE);}}sleep(10);return 0;}



0 0