用C语言编写程序:生产者和消费者之间实现同步与互斥问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用C语言编写程序:生产者和消费者之间实现同步与互斥问题相关的知识,希望对你有一定的参考价值。

程序尽量设计简单短小易懂,如有说明更好..希望会的朋友多多帮助.小弟把分全送上...
我学文的,一个朋友叫我帮他找的。你能帮做的话你就假设下是一个消费者和一个生产者吧,题目没有规定..

//整个程序以伪代码形式给出,当做一个提示吧,这样你同学就应该有思路了
//程序中有注释部分和需要他自己完善的部分,我给的是框架
//老师只是要求用C程序模拟这个机制来实现,就是通过你所学的知识模拟一个效果即可
//利用P,V操作使得在同一时刻,生产者和消费者只能有一个对存储区操作(即临界区)。
//如果两者同时对存储区操作,即同时取和生产的话,必定会有一个等待,当另一个完成操作后自己才会被唤醒。
//生产者在存储区满时不能再生产,进入等待,消费者同理
//完成同步互斥效果
//希望对你朋友有启发

/*----以下为代码部分-----*/

//定义全局变量
int empty = 1;//信号量表示存储单元空,可以生产产品
int full = 0;//信号量表示存储单元空,不可以消费产品

//P操作
void P(int &mutex)

*mutex--;
if(*mutex<0)

//当前进程挂起的程序实现



//V操作
void V(int &mutex)

*mutex++;
if(*mutex <=0)

//唤醒等待中的进程程序实现



//生产者程序
void producer()

P(& empty);//若此时存储区空,则可以生产,否则程序挂起等待

//生产一个产品操作

V(&full);//通知消费者进程,可以取产品



//消费者程序
void consumer()
P(&full);//若此时存储区不空,则可以取产品,否则消费者程序挂起等待

//取走一个产品操作

V(& empty);//通知生产者进程可以生产


//主函数
void main()

//分别调用生产者,消费者程序,顺序不限,因为已经完成信号量的同步,若发生同步问题就会等待

producer();
consumer();
consumer();
producer();

………………

参考技术A //整个程序以伪代码形式给出,当做一个提示吧,这样你同学就应该有思路了
//程序中有注释部分和需要他自己完善的部分,我给的是框架
//老师只是要求用C程序模拟这个机制来实现,就是通过你所学的知识模拟一个效果即可
//利用P,V操作使得在同一时刻,生产者和消费者只能有一个对存储区操作(即临界区)。
//如果两者同时对存储区操作,即同时取和生产的话,必定会有一个等待,当另一个完成操作后自己才会被唤醒。
//生产者在存储区满时不能再生产,进入等待,消费者同理
//完成同步互斥效果
//希望对你朋友有启发
/*----以下为代码部分-----*/
//定义全局变量
int
empty
=
1;//信号量表示存储单元空,可以生产产品
int
full
=
0;//信号量表示存储单元空,不可以消费产品
//P操作
void
P(int
&mutex)

*mutex--;
if(*mutex<0)

//当前进程挂起的程序实现


//V操作
void
V(int
&mutex)

*mutex++;
if(*mutex
<=0)

//唤醒等待中的进程程序实现


//生产者程序
void
producer()

P(&
empty);//若此时存储区空,则可以生产,否则程序挂起等待
//生产一个产品操作
V(&full);//通知消费者进程,可以取产品

//消费者程序
void
consumer()
P(&full);//若此时存储区不空,则可以取产品,否则消费者程序挂起等待
//取走一个产品操作
V(&
empty);//通知生产者进程可以生产

//主函数
void
main()

//分别调用生产者,消费者程序,顺序不限,因为已经完成信号量的同步,若发生同步问题就会等待
producer();
consumer();
consumer();
producer();
………………
参考技术B //整个程序以伪代码形式给出,当做一个提示吧,这样你同学就应该有思路了
//程序中有注释部分和需要他自己完善的部分,我给的是框架
//老师只是要求用C程序模拟这个机制来实现,就是通过你所学的知识模拟一个效果即可
//利用P,V操作使得在同一时刻,生产者和消费者只能有一个对存储区操作(即临界区)。
//如果两者同时对存储区操作,即同时取和生产的话,必定会有一个等待,当另一个完成操作后自己才会被唤醒。
//生产者在存储区满时不能再生产,进入等待,消费者同理
//完成同步互斥效果
//希望对你朋友有启发
/*----以下为代码部分-----*/
//定义全局变量
int
empty
=
1;//信号量表示存储单元空,可以生产产品
int
full
=
0;//信号量表示存储单元空,不可以消费产品
//P操作
void
P(int
&mutex)

*mutex--;
if(*mutex<0)

//当前进程挂起的程序实现


//V操作
void
V(int
&mutex)

*mutex++;
if(*mutex
<=0)

//唤醒等待中的进程程序实现


//生产者程序
void
producer()

P(&
empty);//若此时存储区空,则可以生产,否则程序挂起等待
//生产一个产品操作
V(&full);//通知消费者进程,可以取产品

//消费者程序
void
consumer()
P(&full);//若此时存储区不空,则可以取产品,否则消费者程序挂起等待
//取走一个产品操作
V(&
empty);//通知生产者进程可以生产

//主函数
void
main()

//分别调用生产者,消费者程序,顺序不限,因为已经完成信号量的同步,若发生同步问题就会等待
producer();
consumer();
consumer();
producer();
………………
参考技术C //整个程序以伪代码形式给出,当做一个提示吧,这样你同学就应该有思路了
//程序中有注释部分和需要他自己完善的部分,我给的是框架
//老师只是要求用C程序模拟这个机制来实现,就是通过你所学的知识模拟一个效果即可
//利用P,V操作使得在同一时刻,生产者和消费者只能有一个对存储区操作(即临界区)。
//如果两者同时对存储区操作,即同时取和生产的话,必定会有一个等待,当另一个完成操作后自己才会被唤醒。
//生产者在存储区满时不能再生产,进入等待,消费者同理
//完成同步互斥效果
//希望对你朋友有启发
/*----以下为代码部分-----*/
//定义全局变量
int
empty
=
1;//信号量表示存储单元空,可以生产产品
int
full
=
0;//信号量表示存储单元空,不可以消费产品
//P操作
void
P(int
&mutex)

*mutex--;
if(*mutex<0)

//当前进程挂起的程序实现


//V操作
void
V(int
&mutex)

*mutex++;
if(*mutex
<=0)

//唤醒等待中的进程程序实现


//生产者程序
void
producer()

P(&
empty);//若此时存储区空,则可以生产,否则程序挂起等待
//生产一个产品操作
V(&full);//通知消费者进程,可以取产品

//消费者程序
void
consumer()
P(&full);//若此时存储区不空,则可以取产品,否则消费者程序挂起等待
//取走一个产品操作
V(&
empty);//通知生产者进程可以生产

//主函数
void
main()

//分别调用生产者,消费者程序,顺序不限,因为已经完成信号量的同步,若发生同步问题就会等待
producer();
consumer();
consumer();
producer();
………………
参考技术D //整个程序以伪代码形式给出,当做一个提示吧,这样你同学就应该有思路了
//程序中有注释部分和需要他自己完善的部分,我给的是框架
//老师只是要求用C程序模拟这个机制来实现,就是通过你所学的知识模拟一个效果即可
//利用P,V操作使得在同一时刻,生产者和消费者只能有一个对存储区操作(即临界区)。
//如果两者同时对存储区操作,即同时取和生产的话,必定会有一个等待,当另一个完成操作后自己才会被唤醒。
//生产者在存储区满时不能再生产,进入等待,消费者同理
//完成同步互斥效果
//希望对你朋友有启发
/*----以下为代码部分-----*/
//定义全局变量
intempty=1;//信号量表示存储单元空,可以生产产品
intfull=0;//信号量表示存储单元空,不可以消费产品
//P操作
voidP(int&mutex)

*mutex--;
if(*mutex<0)

//当前进程挂起的程序实现


//V操作
voidV(int&mutex)

*mutex++;
if(*mutex<=0)

//唤醒等待中的进程程序实现


//生产者程序
voidproducer()

P(&empty);//若此时存储区空,则可以生产,否则程序挂起等待
//生产一个产品操作
V(&full);//通知消费者进程,可以取产品

//消费者程序
voidconsumer()
P(&full);//若此时存储区不空,则可以取产品,否则消费者程序挂起等待
//取走一个产品操作
V(&empty);//通知生产者进程可以生产

//主函数
voidmain()

//分别调用生产者,消费者程序,顺序不限,因为已经完成信号量的同步,若发生同步问题就会等待
producer();
consumer();
consumer();
producer();
………………

用信号量进程同步与互斥

---恢复内容开始---

1.理解生产者和消费者问题

没有引入信号量时的生产者和消费者进程,什么情况下会出现结果不唯一?什么情况下会出现永远等待?

用信号解决生产者和消费者的同步与互斥,要求能自己写出来。

答:在两个进程同时进行时,结果会不唯一,因为不同步。

由于异常的中断,导致判断条件的重复错误,最后导致永远等待。

 2.哲学家吃面问题

#include<iostream>
#include<thread>
#include<mutex>
#include<ctime>
using namespace std;
using namespace std::this_thread;
using namespace std::chrono;
//用五个互斥量表示五支叉子
mutex fork[5];
//用一个规模为5的整型数组来表示每个盘子剩余的面条
int nuddles[5] = { 50,50,50,50,50 };
//吃面条函数
void eat(int id) {
	//id为哲学家编号
	while (true) {
		//尝试同时拿起左手边和右手边的叉子
		if (fork[id].try_lock()) {
			//先尝试拿起左手边的叉子
			//如果能拿起左手边的叉子,再拿右手边的
			if (fork[(id + 1) % 5].try_lock()) {
				//如果也能拿起右手边的叉子,吃面条
				//开吃,每次吃掉的面条数量为10-20之间的一个数字
				printf("哲学家%d开始吃面条!\n", id + 1);
				srand((unsigned)time(NULL));
				int numbereated = rand() % (20 - 10 + 1) + 10;
				sleep_for(seconds(numbereated % 10));//吃一段时间
				nuddles[id] -= numbereated;
				if (nuddles[id] <= 0) {
					printf("                          哲学家%d吃完了他的所有面条!\n", id+1);
					fork[id].unlock();
					fork[(id + 1) % 5].unlock();
					break;
				}
				printf("哲学家%d吃完,面条剩余%d!\n", id+1, nuddles[id]);
				fork[id].unlock();
				fork[(id + 1) % 5].unlock();
				sleep_for(milliseconds(200));//吃完之后歇一会,让其它哲学家能够吃上
			}
			else {
				//如果没办法拿起右手边的叉子,记得要把左手边的叉子放下来
				fork[id].unlock();
				sleep_for(milliseconds(100));//歇一会(思考),让其它哲学家能够吃上
			}
		}
	}
}
 
int main()
{
	printf("开始吃饭!每人拥有50面条\n");
	thread t1(eat, 0);
	thread t2(eat, 1);
	thread t3(eat, 2);
	thread t4(eat, 3);
	thread t5(eat, 4);
	t1.join(); t2.join(); t3.join(); t4.join(); t5.join();
	printf("所有哲学家吃完!\n");
	return 0;
}
参考代码。

3.读写文件问题

nt readcount=0;

semaphore writeblock=1,mutex=1;

cobegin

process reader_i() {

         P(mutex);

       readcount++;

        if(readcount==1)

          P(writerblock);

          V(mutex);

          /*读文件*/

         P(mutex);

         readcount--;

         if(readcount==0)

                  V(writeblock);

           V(mutex);  }

coend

4.理发师问题

int waiting=0, chairs=n;

semaphore customers=0,barbers=0,mutex=1;

cobegin

     process barbers() {

           while(ture) {

                P(customers);

                P(mutex);

                waiting--;

                V(barbers); 

                V(mutex);

                cuthair();  } }

process customer_i() {

               P(mutex);

               if(waiting<chairs) {

                     waiting++;

                      V(customers);

                       V(mutex);

                       P(barbers):

                       get_haircut();

}

else

        V(mutex);

}

coend

5.在一间酒吧里有三个音乐爱好者队列,第一队的音乐爱好者只有随身听,第二队只有音乐磁带,第三队只有电池。而要听音乐就必须随身听、音乐磁带和电池这三种物品俱全。酒吧老板一次出售这三种物品中的任意两种。当一名音乐爱好者得到这三种物品并听完一首乐曲后,酒吧老板才能再一次出售这三种物品中的任意两种。于是第二名音乐爱好者得到这三种物品,并开始听乐曲。全部买卖就这样进行下去。试用P,v操作正确解决这一买卖。

semaphore muext=1;

cobegin

process boss(){

             P(muext);

            /*老板任意出售两种*/

             V(muext);

}

 

process musiclovers_i() {

               while(ture){

                P(muext);

                 listening();

                V(muext);

}  }

coend

 

6.某银行有人民币储蓄业务,由n个储蓄员负责。每个顾客进入银行后先取一个号,并且等着叫号。当一个储蓄人员空闲下来,就叫下一个号。请用P,V操作正确编写储蓄人员和顾客进程的程序。

semaphore customers=0,clerk=0,mutex=n;

int waiting=0;

cobegin

  process clerk() {

                   while(ture){

                            P(customers);

                            P(mutex);

                            waiting--;

                            V(clerk);

                            V(mutex);

                             service();

} }

 

process customer_i() {

 

                     P(mutex);

 

                     waiting++;

 

                      V(customers);

 

                       V(mutex);

 

                       P(clerk):

 

                       get_service();

 

}

coend

 

 

7.下面是两个并发执行的进程。它们能正确运行吗?若不能请举例说明,并改正之。(5分)

parbegin

    var X:integer;

    process  P1                    process  P2

    var y,z:integer:            var t,u:integer;

     begin                          begin

       x:=1;                           x:=0:

       y:=0:                           t=0;   

       if  x≥l  then y:=y十1;    if  x≤l  then  t:=t+2;

            z:=y;                           u:=t;

     end;                         end;

parend.

 

parbegin

var x:integer; var s:semaphore:=1;

process P1                                   process P2

       var y,z:integer ;                             var ,tu:integer ;

begin                                           begin

      P(s);                                           P(s);

      x:=1;                                         x:=0;

      y:=0;                                         t:=0;

        if x>=1 then y:=y+1;                   if x<=1 then t:=t+2

      V(s);                                            V(s);

         z:=y;                                           u:=t;

end                                                end

parend

 

8.九、在一个盒子里,混装了相等数量的黑棋子和白棋子,现要用自动分拣系统把黑棋子和白棋子分开,该系统由两个并发执行的进程P1和P2组成,其中进程P1专门拣黑子,进程P2专门拣白子。规定两个进程轮流拣子且每个进程每次只拣一个子。当一个进程在拣子时不允许另一个进程去拣子,并设P1先拣。请用P,V操作管理这两个并发进程,使其能正确实现上述功能。

semaphore s1=1,s2=0;

cobegin {

      process P1

         begin

            repeat

                P(s1);

                 拣黑子;

                V(s2);

              until false;

           end

  process P2

         begin

            repeat

                P(s2);

                 拣白子;

                V(s1);

              until false;

           end

}

coend

以上是关于用C语言编写程序:生产者和消费者之间实现同步与互斥问题的主要内容,如果未能解决你的问题,请参考以下文章

用C语言实现--生产者与消费者的问题(PV操作)

用信号量进程同步与互斥

如何使用互斥锁在 C 中执行生产者-消费者程序

用信号量进程同步与互斥

用信号量进程同步与互斥

用信号量进程同步与互斥