信号量实现生产者消费者问题 window linux

时间:2021-12-09 15:14:10

 1. 在Windows操作系统上,利用Win32API提供的信号量机制,编写应用程序实现生产者——消费者问题。

2. 在Linux操作系统上,利用Pthread API提供的信号量机制,编写应用程序实现生产者——消费者问题。

3. 两种环境下,生产者和消费者均作为独立线程,并通过empty、full、mutex三个信号量实现对缓冲进行插入与删除。

4. 通过打印缓冲区中的内容至屏幕,来验证应用程序的正确性。

㈠设计思路

①声明三个信号量,互斥信号量mutex,计数信号量empty初始化值100,技术信号量full初始化值0,并声明一个缓冲区char类型的buffer数组,大小为10,初始值为N。

②produce利用信号量形成对buffer临界生产,添加一个元素进去,赋值为A。consume利用信号量形成对buffer临界消费,从buffer中拿出来一个元素,并将buffer中原来元素赋为B。每访问一次临界区,就输出buffer值。

③创建多线程,其中5个生产者,和5个消费者,每个线程最多操作缓冲区10次。

㈡流程图

 

声明一个char类型的数组buffer,大小为10,用来做生产者和消费者共同访问的共享变量,可视做临界区。

Win32下
#include <IOSTREAM.h>
#include <STDIO.H>
#include <windows.h>
HANDLE Empty,full,mutex;//声明3个信号量,互斥信号量mutex,计数信号量full和Empty
int x=0;
int y=0;
char *buffer;//缓冲区buffer
//输出buffer
void output()
{
for (int i=0;i<10;i++)
{
cout<<buffer[i]<<" ";
}
cout<<"\n";
}
DWORD WINAPI produce(LPVOID param)
{
int j=0;
do
{
WaitForSingleObject(Empty,INFINITE);//buffer空余量减一
WaitForSingleObject(mutex,INFINITE);//形成互斥,只能一个线程去生产
cout<<GetCurrentThreadId()<<"^^^^^"<<j<<"^^^^^";
//输出当前线程的id号,和执行的次数
buffer[(y++%10)]='A';//生产赋值为A
output();//输出buffer
j++;
ReleaseSemaphore(mutex,1, NULL);//取消互斥,允许其他线程生产
ReleaseSemaphore(full,1, NULL);//可以消费量加1
} while (j!=10);//每个线程生产10次
return 0;
}
DWORD WINAPI consume(LPVOID param)
{
int j=0;
do
{
WaitForSingleObject(full,INFINITE);//将可以消费量减1
WaitForSingleObject(mutex,INFINITE);//形成互斥访问,自能一个线程可以访问。
cout<<GetCurrentThreadId()<<"*****"<<j<<"*****";
buffer[x++%10]='B';//消费时,赋值为B
output();//输出buffer
j++;
ReleaseSemaphore(mutex,1, NULL);//取消互斥,允许其他线程消费
ReleaseSemaphore(Empty,1, NULL);//buffer空余量加1
} while (j!=10);//每个线程可以消费10次
return 0;
}
int main()
{
int i;
Empty=CreateSemaphore(NULL,10,10,NULL);//声明计数信号量,Empty初值为10
full=CreateSemaphore(NULL,0,10,NULL);//声明技术信号量,full初值为0
mutex=CreateSemaphore(NULL,1,1,NULL);//申明互斥信号量,初值为1
//初始化buffer数组,大小为0
buffer=new char[10];
for (i=0;i<10;i++)
{
buffer[i]='N';
}
//HANDLE thread;
DWORD *ThreadId=(DWORD *)malloc(10*sizeof(DWORD*));
HANDLE*ThreadHandle=(HANDLE)malloc(10*sizeof(HANDLE));//创建线程句柄,分配空间
//创建5个生产者线程和5个消费者线程
for (i=0;i<5;i++)
{ThreadHandle[i+5]=CreateThread(NULL,0,produce,NULL,0,&ThreadId[i+5]);ThreadHandle[i]=CreateThread(NULL,0,consume,NULL,0,&ThreadId[i]);
}
//让所有线程在主线程main()执行完钱全部执行完毕。
WaitForMultipleObjects(10,ThreadHandle,TRUE,INFINITE);
return 0;
}

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

#define BUFFER_SIZE 10//缓冲区大小为10
char *buffer;
sem_t mutex,empty,full;//三个信号量,互斥信号量mutex,技术信号量empty和full
int x,y;//生产者和消费者在buffer中下标
void output()//输出buffer数组
{
int i;
for(i=0;i<BUFFER_SIZE;i++)
{
printf("%c",buffer[i]);
printf(" ");
}
printf("\n");
}
void *produce()//生产者函数
{
int j;
j=0;
do
{
sem_wait(&empty);//buffer有空余部分,可以生产,并减一
sem_wait(&mutex);//形成互斥访问,只能一个线程生产
printf("%lu%s%d%s",pthread_self(),"^^^^^",j,"^^^^^ ");//输出当前线程的id号,以及正在执行的次数
buffer[(x++)%BUFFER_SIZE]='A';//生产就赋值A
output();//输出buffer
j++;
sem_post(&mutex);//取消互斥
sem_post(&full);//生成完毕,增加一个可以消费量。
}while (j!=30);//每个线程可以做30次
}
void *consume()//消费者函数
{
int j;
j=0;
do
{
sem_wait(&full);//可以消费的量减一
sem_wait(&mutex);//互斥访问,只能一个线程消费
printf("%lu%s%d%s",pthread_self(),"*****",j,"***** ");
buffer[(y++)%BUFFER_SIZE]='B';//消费时,赋值为B
output();//输出buffer值
j++;
sem_post(&mutex);//取消互斥,其他线程可以消费
sem_post(&empty);//空余量加一
}while (j!=30);//每个线程可以消费30次
}

int main()
{
int i;
x=0;
y=0;
buffer=(char*)malloc(BUFFER_SIZE*sizeof(char*));
for(i=0;i<BUFFER_SIZE;i++)//初始化buffer数组,默认为N
{
buffer[i]='N';
}
//semaphore
sem_init(&mutex,1,1);//初始化互斥信号量mutex为1
sem_init(&empty,0,BUFFER_SIZE);//初始化计数信号量empty为BUFFER_SIZE
sem_init(&full,0,0);//初始化计数信号量full为0
//multipthread
pthread_t tid[10];
pthread_attr_t attr;
pthread_attr_init(&attr);
//创建5个生产者线程和5个消费者线程
for(i=0;i<5;i++)
{
pthread_create(&tid[i],&attr,consume,NULL);
pthread_create(&tid[i+5],&attr,produce,NULL);
}
//让每个线程在主线程main执行前全部执行完毕。
for(i=0;i<10;i++)
{
pthread_join(tid[i],NULL);
}
return 0;
}