代码的关键部分是设置一个互斥量来模仿只有一个线程访问缓冲区。
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> //设计缓冲区 #define N 4//缓冲区大小 int buf[N] = {0};//缓冲区初始化为0,表示一开始没有产品 int putin = 0;//数据入区位置 int takeout = 0;//数据出区位置 //设计信号量(信号量的大小可为>1的数) sem_t unoccupied;//空位个数时 sem_t occupied;//产品各数 //设置互斥量(互斥量的大小为0或1) pthread_mutex_t mutex; //表示一个缓冲区,模拟操作系统只有一个线程对缓冲区访问,不能同时有多个线程访问缓冲区 //设计时延函数(2层循环) void delay (int len) { int i = rand () % len; int x; while (i > 0) { x = rand () % len; while (x > 0) { x--; } i--; } } //设计可唤醒消费者的生产者 void producer() { while (1) { //模拟正在生产 int d = 1 + rand () % 100;//代表生产的产品名字 delay(50000); //生产后产品入库 sem_wait(&unoccupied);//P操作,将对应的信号量unoccupied减1再与0进行比较大小,入库前判断是否有空位,有空位(比较结果>=0)则后续代码才能执行,否则阻塞当前进程 //开始业务操作 pthread_mutex_lock(&mutex); //加锁,当一个线程在访问缓冲区时,另一个线程来访问时被阻塞 buf[putin] = d; printf("Put %d to the buffer at %d.\n",buf[putin],putin); putin++; if(putin == N) {//生产出的产品的投放顺序在缓冲区依序排放,即使前一个生产出的产品被消耗了,也是依序往后放 putin = 0;//putin变为3以后自增为4的时将其置0 } sem_post(&occupied);//V操作,可取物品信号量加1,唤醒 pthread_mutex_unlock(&mutex); //当前线程访问完缓冲区以后解锁 } } void consumer() { while (1) { //模拟正在取物品 delay(5000); //进行消费 sem_wait(&occupied);//P操作,将对应的信号量occupied减1再与0进行比较大小,消费前判断是否有产品,有产品(比较结果>=0)则后续代码才能执行,否则阻塞当前进程 pthread_mutex_lock(&mutex); printf("Take out %d from the buffer at %d.\n",buf[takeout],takeout); buf[takeout] = -1; takeout++; if (takeout == N) { takeout = 0; } sem_post(&unoccupied);//V操作,可生产空位信号量加1 pthread_mutex_unlock(&mutex); } } int main () { srand(time(NULL)); //声明厂家消费者线程 pthread_t manufacturer; pthread_t customer; //初始化信号量 sem_init(&unoccupied, 0, N); sem_init(&occupied, 0, 0); //初始化互斥量 pthread_mutex_init(&mutex, NULL); //创建线程 pthread_create(&manufacturer, NULL, (void *)producer, NULL); pthread_create(&customer, NULL, (void *)consumer, NULL); //阻塞当前线程,直到t1和t2线程执行结束 pthread_join(manufacturer, NULL); pthread_join(customer, NULL); //撤销信号量 sem_destroy(&unoccupied); sem_destroy(&occupied); return 0; }