实验前知识准备
1.生产者消费者问题是一个著名的进程同步问题,本次实验中,用线程代替进程。
源代码
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFFER_SIZE 10//缓冲池容量,选择循环队列这种数据结构
int* buffer;//指针在开辟空间时用到
int front = 0;//队头
int rear = 0;//队尾
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//POSIX 定义了一个宏
PTHREAD_MUTEX_INITIALIZER 来静态初始化互斥锁,在 LinuxThreads 实现中,
pthread_mutex_t 是一个结构,而 PTHREAD_MUTEX_INITIALIZER 则是一个结构常量
sem_t empty, full;//定义另一种信号量:条件变量
static void* Producer_T(void* arg) //生产者
{
printf("Producer run\n");
消费者
wait(full)
缓冲区非空
wait(mutex)
自缓冲区取出产品
结束
缓冲区被占用
缓冲区为空
signal(empty)
signal(mutex)
for (int i = 0; i < 10; i++) //生产 10 次 {
sem_wait(&empty);//是否有空余缓冲区,必须先 wait(empty)
pthread_mutex_lock(&mutex);//有空缓冲区就申请互斥锁修改缓冲区
buffer[front] = i;
front = (front + 1) % BUFFER_SIZE;//循环队列加一操作
printf("Producer: produce a good %d and put it into buffer\n", i);
pthread_mutex_unlock(&mutex);//放锁,和下面对 full 加一可以调换顺序
sem_post(&full);
sleep(1);//一秒生产一次
} }
static void* Consumer_T(void* arg) //消费者
{
printf("Consumer run\n");
for (int i = 0; i < 10; i++)
{
sem_wait(&full);//是否有存在产品的缓冲区,必须先 wait(full)
pthread_mutex_lock(&mutex);//有产品就申请互斥锁修改缓冲区
rear = (rear + 1) % BUFFER_SIZE;//循环队列减一操作
printf("Consumer: gain a good %d from buffer\n", buffer[rear]);
pthread_mutex_unlock(&mutex);//放锁,和下面对 empty 加一可以调换顺序
sem_post(&empty);
sleep(5);//五秒取一次产品
} }
int main()
{
pthread_t Producer, Consumer;//管理两个线程
void* Ret_P, * Ret_C;//两个空指针,作为创建线程时的一个参数
buffer = (int*)malloc(BUFFER_SIZE * sizeof(int));//给循环队列动态分配BUFFER_SIZE 大小的空间
if (pthread_create(&Producer, NULL, Producer_T, NULL) != 0 ||
pthread_create(&Consumer, NULL, Consumer_T, NULL) != 0)
{
printf("pthread_create error\n");
return -1;
}//生产者消费者两个线程创建是否成功
if ( sem_init(&empty, 0, BUFFER_SIZE) == -1||sem_init(&full, 0, 0) == -1 )
{
printf("sem_init error\n");
return -2;//信号量初始化是否成功
}
//后续都为资源的回收工作
pthread_join(Producer, &Ret_P);
pthread_join(Consumer, &Ret_C);//考虑到在多线程的程序中,主控线程一旦运行结束,所有的相关子线程将也会被强制结束。调用 pthread_join(),一方面使主线程等待子线程运行结束再运行,给子线程运行时间,另一方面,可以回收线程资源
free(buffer);
sem_destroy(&full);
sem_destroy(&empty);
return 0;
}