- 实验目的
1、熟悉并发程序实验工具BACI。
2、掌握BACC和BAINTERP的使用。
3、熟悉信号量的同步控制机制。
二、实验软硬件要求
** ** 1、CPU:P4 1.6GHz 内存:4G
2、Windows平台上的Linux虚拟机
- 实验内容
(1)完成Linux系统的登录,启动进入终端。
编程步骤:
cd baci/balnxxe
编写程序文件命令:gedit my.cm (程序源码请看第(2)题,需要你补充缺失的代码。)
编译命令:$./bacc my,生成my.pco文件;
运行:./bainterp my.pco, 得到并分析结果。
(2)用信号量实现进程同步时,通常设置与进程相关的私有信号量。empty和full分别属于生产者和消费者进程私有,即生产者要问是否empty,才能开始生产;同理,消费者要问是否full才能消费。 用信号量mutex实现进程互斥,互斥使用缓冲池,其初值=1;
请将下面的并发程序填写完整,或自行编写并发程序。
参考程序:pc.cm
semaphore mutex=1; //缓冲池互斥信号量
semaphore full=0; //满缓冲区个数信号量,初值=0
semaphore em=7; //空缓冲区个数信号量,初值=7
int in=0;int out=0;
int buff[6]; //缓冲池
void p1()
{ int nextp; while(1)
{ cin>>nextp; //生产一个产品
p(em);
//填写代码
buff[in]=nextp;
cout <<"in="<<in<<endl;
//填写代码;
cout <<"nextp="<<nextp<<endl;
v(mutex);
//填写代码;
}
}//producer
void c1()
{ int nextc;
while(1)
{
//填写代码;
p(mutex);
//填写代码
out=(out+1)%6;
cout <<"nextc="<<nextc<<endl;
//填写代码;
v(em);
}
}//consumer
void main()
{ cobegin{ p1();c1(); }
}
完整代码:
semaphore mutex=1;
semaphore full=0;
semaphore em=7;
int in=0;int out=0;
int buff[6];
void p1(){
int nextp;
while(1){
cin>>nextp;
p(em);
p(mutex);
buff[in]=nextp;
cout<<"in="<<in<<endl;
in=(in+1)%6;
cout<<"nextp="<<nextp<<endl;
v(mutex);
v(full);
}
}
void c1(){
int nextc;
while(1){
p(full);
p(mutex);
nextc=buff[out];
out=(out+1)%6;
cout<<"nextc="<<nextc<<endl;
v(mutex);
v(em);
}
}//consumer
void main(){
cobegin{
p1();
c1();
}
}
(3)有父亲、母亲、儿子、女儿4个进程,共享一个盘子,父亲每次在盘子中放入一个苹果,盘子中的苹果只能由女儿取出;母亲每次向盘子放入一个桔子,桔子只能由儿子取出,假设盘子内能装一个水果。编程:apple.cm
1)编写用信号量机制实现父亲等4个进程的并发控制程序;
2)在BACI环境中运行并分析结果。
semaphore mutex=1;
semaphore plat=1;
semaphore apple=0;
semaphore orange=0 ;
int ap=0;int or=0;int pl=1;
void father(){
int num;
while(1){
p(plat);
p(mutex);
cin>>num;
cout<<"father put on apple "<<num<<endl;
v(apple);
ap++;
pl--;
v(mutex);
}
}
void monther(){
int num;
while(1){
p(plat);
p(mutex);
cin>>num;
cout<<"monther put on orange "<<num<<endl;
v(orange);
or++;
pl--;
v(mutex);
}
}
void son(){
int num;
while(1){
p(orange);
p(mutex);
cout<<"son take out a orange"<<endl;
v(plat);
or--;
pl++;
cout<<"orange="<<or<<endl;
cout<<"plat="<<pl<<endl;
v(mutex);
}
}
void daughter(){
int num;
while(1){
p(apple);
p(mutex);
cout<<"daughter take out a apple"<<endl;
v(plat);
ap--;
pl++;
cout<<"apple="<<ap<<endl;
cout<<"plat="<<pl<<endl;
v(mutex);
}
}
void main(){
cobegin{
father();
daughter();
monther();
son();
}
}
三、实验结果分析
(对上述实验内容中的各题结果,进行分析讨论。并回答下列问题)
- 简述用信号量控制互斥问题时的编程设置。
当进程互斥时或者涉及临界资源的争夺时,应该遵循前P后V的信号量设置原则
- 简述用信号量控制同步问题时的编程设置。
当进程同步时,应该遵循前V后P的原则,即先发生的进程完成后设置V信号量,后发生的进程发生前设置P信号量,同时注意,PV信号量应该成对出现。
四、总结:你对本次实验有什么体会或看法。
分析信号量问题时,应该先进行关系分析,找出同步和互斥的关系,根据同步关系前V后P ,互斥关系前P后V的原则对信号量进行设置。
注意:伪代码中设置的semaphore是信号量,只能用PV进行加减,不能使用++或—进行操作。
附BACI工具说明:
BACI提供了一个可以编写并发程序的环境,在这个平台上,我们可以很容易的模拟程序的并发执行,在这种并行的编译环境中,可以把BACI中的一些语句嵌入到C++,C,Java等高等程序中,使程序可以并行执行 .
基于C++的BACI语法(C—BACI Compiler)
该语法结构是在C++语法结构的基础上,增加一些并发语句扩展而来,下面是在试验中需要用到的函数解释.
- cobegin函数
在BACI系统中,并发进程与并发线程同步,多个进程可以并发的在cobegin 块中来并发执行,该函数必须在主函数中,语法结构为:
cobegin {
proc1(...);proc2(...);. . . . procN(...);
}
其中每个进程并发随机执行,每次执行的顺序可能会不一样,当所有的进程接受后,该函数结束。
- Semaphores/Binarysem
信号量的(Semaphores)机制可以更方便的实现进程同步,Semaphores是一种如C中”int”一样的类型,可以用来定义信号量类型的变量,Binarysem是一种二进制信号量,它所定义的变量只能取1或 0,用来表示互斥。
1)信号量的声明和初始化
semaphores a;
binarysem s;
上面声明了两个信号量a,b,其中b为二进制信号量信号量按如下方式初始化:
Initialsem(semaphores,interger);
Initialsem(binarysem,0/1);
2)P(wait)/V(signal)函数
强大的PV操作与信号量一次很方便的解决了并发进程同步与互斥问题
函数原型:
void p(semaphores &s); or void wait(semaphores &s);
void v(semaphores &s); or void signal(semaphores &s);
函数说明:
p(sem): 如果sem > 0,则sem减1,调用P的进程可以继续执行,如果sem=0,则该进程阻塞,该函
数操作是原子性的.
v(sem): 如果v=0,或有进程阻塞,则将其唤醒,如果没有进程等待,将sem加1,在任何时候调用
v的进程可以继续执行,其操作也是原子的.
3.atomic
atomic关键字定义了原子操作,即该函数操作不可剥夺,每次只能一个进程访问
用法:在要原子执行的函数前加atomic即可,如:
atomic int sum(){
. . . ..
}
则sum()函数就可以原子操作了
4.void suspend(void)
suspend函数将调用的线程挂起
5.void revive (int process_number)
该函数用于唤醒某个进程,其进程号为process_number
6.cin可以连续从键盘读取想要的数据,以空格、tab或换行作为分隔符。
版权归原作者 忘崽奶糖~ 所有, 如有侵权,请联系我们删除。