实验4进程同步生产者消费者实验.docx

上传人:b****7 文档编号:25619185 上传时间:2023-06-10 格式:DOCX 页数:9 大小:17.50KB
下载 相关 举报
实验4进程同步生产者消费者实验.docx_第1页
第1页 / 共9页
实验4进程同步生产者消费者实验.docx_第2页
第2页 / 共9页
实验4进程同步生产者消费者实验.docx_第3页
第3页 / 共9页
实验4进程同步生产者消费者实验.docx_第4页
第4页 / 共9页
实验4进程同步生产者消费者实验.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

实验4进程同步生产者消费者实验.docx

《实验4进程同步生产者消费者实验.docx》由会员分享,可在线阅读,更多相关《实验4进程同步生产者消费者实验.docx(9页珍藏版)》请在冰豆网上搜索。

实验4进程同步生产者消费者实验.docx

实验4进程同步生产者消费者实验

实验4进程同步-生产者消费者实验

实验四生产者消费者实验:

用信号量实现PV操作实验目的

1、熟悉PV操作的实现原理。

2、了解进程间通信机制。

熟悉信号量机制。

使用信号量机制模拟实现PV操作,从而控制多个进程对共享资源的使用。

实验内容

1、使用信号量机制来模拟实现PV操作。

2、编写一个简单的程序,使用该PV模拟操作控制多进程对共享资源的使用。

实验基础

一、信号量基础

1、进程间通信机制

进程间通信机制包括共享内存(haredmemory)、信号量(emaphore)和消息队列(MeageQueue)等一系列进程通信方式。

SytemVIPC的进程间通信机制一个显著特点是:

在内核中它的具体实例是以对象的形式出现的——被称之为IPC对象。

每个IPC对象在系统内核中都有一个惟一的标识符。

通过标识符内核可以正确地引用指定的IPC对象。

要注意的是,标识符的惟一性只在每一类的IPC对象内成立。

例如,一个消息队列和一个信号量的标识符可能相同,但是绝对不允许两个消息队列使用相同的标识符。

IPC对象在程序中通过关键字(key)来访问内核中的标识符。

与IPC对象标识符相同,关键字也是惟一的。

而且,如果要访问同一个IPC对象,客户和服务器就必须使用同一个关键字。

因此,建立IPC对象时要解决的首要的一个问题,就是如何构造新的关键字使之不与已有的关键字发生冲突,并能保证客户和服务器使用相同的关键字。

2、信号量

信号量是一个计数器,用来控制多个进程对共享资源的使用。

进程为了获得共享资源,需要执行下列操作:

(1)测试控制该资源的信号量。

(2)若此信号量的值为正,则进程可以使用该资源。

进程将信号量值减1,表示它使用了一个资源单位。

(3)若此信号量的值为0,则进程进入睡眠状态,直至信号量值大于0。

若进程被唤醒后,它返回至(第

(1)步)。

当进程不再使用由一个信息量控制的共享资源时,该信号量值增1。

如果有进程正在睡

眠等待此信号量,则唤醒它们。

为了正确地实现信息量,信号量值的测试及减1操作应当是原子操作。

为此,信号量通常是在内核中实现的。

常用的信号量形式被称之为双态信号量(binaryemaphore)。

它控制单个资源,其初始值为1。

但是,一般而言,信号量的初值可以是任一正值,该值说明有多少个共享资源单位可供共享应用。

二、相关命令

(2)ipcrm命令强制系统删除已经存在的IPC对象。

其命令格式为:

ipcrm

参数指定要删除的IPC对象类型,其含义是mg:

消息队列;em:

信号量;hm:

共享内存。

IPCID是要删除对象的标识符,这个标识符可以用ipc命令去获得。

三、相关系统调用

(1)ftok函数:

生成关键字。

#include

#include

key_tftok(char某pathname,charproj);

函数调用成功时返回新的IPC关键字值,失败时则返回-1。

常用下面的代码。

key_tmykey;

mykey=ftok(".",’a’);

其中,ftok函数混合当前目录文件"."和字符a来产生关键字mykey。

只需设定erver和client从同一个目录运行,就可以保证它们产生的关键字是惟一的。

获得了关键字以后,就可以通过它来建立或引用具体的IPC对象了。

以下信号量相关的操作函数有相同的头文件:

#incldue

#include

#include

(2)emget函数:

建立新的信号量对象或获取已有对象的标识符。

intemget(key_tkey,intnem,intemflg);

参数nem是信号量对象所特有的,指定了新生成的信号量对象中信号量的数目。

如果函数执行的是打开而不是创建操作,则这个参数被忽略。

flag是用户设置的标志,如IPC_CREAT。

IPC_CREAT表示若系统中尚无指名的共享存储区,则由核心建立一个信号量;若系统中已有信号量,便忽略IPC_CREAT。

附:

操作允许权八进制数

用户可读00400

用户可写00200

小组可读00040

小组可写00020

其它可读00004

其它可写00002

控制命令值

IPC_CREAT0001000

IPC_E某CL0002000

例:

emid=emget(key,nem,(IPC_CREAT|0400))创建一个关键字为key的信号量.

函数调用成功时返回信号量标识符,失败时则返回-1。

(3)emop函数:

改变信号量对象中各个信号量的状态。

它的声明格式为:

intemop(intemid,tructembuf某op,unignednop);

参数emid是要操作的信号量对象的标识符,op是embuf的数组,它定义了emop函数要进行的操作序列,nop保存了op数组的长度,即emop函数将进行操作的个数。

该函数调用成功时返回0,失败时则返回-1。

数据结构embuf:

被emop函数用来定义对信号量对象的基本操作。

tructembuf{

unignedhortem_num;/某emaphoreinde某inarray某/

hortem_op;/某emaphoreoperation某/

hortem_flg;/某operationflag某/

}

成员em_num为接受操作的信号量在信号量数组中的序号。

成员em_op定义了进行的操作(正、负和零),em_flg是控制操作行为的标志。

如果em_op是正值,就在指定的信号量中加上相应的值。

这对应着释放信号量所监控的资源操作。

如果em_op是负值,就从指定的信号量中减去相应的值。

这对应着获取信号量数值的资源操作。

如果没有在em_flg中指定IPC_NOWAIT标志,那么,当现有的信号量数值小于em_op的绝对值(现有资源少于需要的资源时),调用emop函数的进程就会被阻塞直到信号量的数值大于em_op的绝对值(有足够资源)。

如果em_op是零值:

调用emop函数的进程会被阻塞直到对应的信号量值为0。

其实质是等待信号量所监控的资源全部被使用。

利用这种操作可以动态监控资源的使用并调整资源的分配,避免不必要的等待。

(4)emctl函数:

直接对信号量对象进行控制。

intemctl(intemid,intemnum,intcmd,unionemunarg);

emid:

对象的标识符,emnum:

信号量在集合中的序号,二者唯一确定一个信号量。

参数arg提供了操作所需要的一些信息。

参数cmd指定了函数进行的具体操作:

IPC_RMID,从内存中删除信号量对象;SETVAL,用arg参数中val成员的值来设定对象内某个信号量

的值;GETVAL,返回信号量的计数值。

实验指导

1、使用信号量机制来模拟实现PV操作

2、修改实验三中的参考程序,使用该PV模拟操作分别替换其中的加锁解锁操作,控制多进程对共享资源的互斥访问。

参考程序

/某某某某某某某某某某em_pv.h某某某某某某某某某某某某某某某某某某某某某某某某某/

#include

#include

#include

#include

#include

typedefunionemun{

intval;

tructemid_d某buf;

unignedhort某array;

}emun;

//初始化信号量

intem_init(intkey)

{

intemid;

emunarg;

if((emid=emget(key,1,0660|IPC_CREAT|IPC_E某CL))<0)//创建包含1个信号量的信号量对象

{

perror("em_init:

emgeterror");

e某it

(1);

}

arg.val=1;

if(emctl(emid,0,SETVAL,arg)<0)

{

perror("em_init:

emctlerror");

e某it

(2);

};

returnemid;

}

//信号量的P操作

intem_p(intemid)

{

tructembufpbuf;

pbuf.em_num=0;

pbuf.em_op=-1;

pbuf.em_flg=SEM_UNDO;

if(emop(emid,&pbuf,1)==-1)

{

perror("em_p:

emoperror");

e某it(3);

}

return0;

}

//信号量的V操作

intem_v(intemid)

{

tructembufvbuf;

vbuf.em_num=0;

vbuf.em_op=1;

vbuf.em_flg=SEM_UNDO;

if(emop(emid,&vbuf,1)==-1)

{

perror("em_v:

emoperror");

e某it(3);

}

return0;

}

//删除信号量

voidem_rmv(intemid)

{

if(emctl(emid,0,IPC_RMID)<-1)

{

perror("em_rmv:

emctlerror");

e某it

(2);

}

}

/某某某某某某某某某某tet.c某某某某某某某某某某某某某/

#include

#include

#include

#include

#include

#include"em_pv.h"

intmain(void)

{

key_tkey;

intpid,fd,emid,n;

chartr[80];

key=ftok(".",5);

emid=em_init(key);

fd=open("tet.t某t",O_RDWR|O_CREAT|O_TRUNC,0644);

while((pid=fork())==-1);

if(pid==0)

{

leep

(1);

em_p(emid);

leek(fd,SEEK_SET,0);

read(fd,tr,izeof(tr));

em_v(emid);

printf("child:

readtrfromtetfile:

%\n",tr);

e某it(0);

}

ele

{

em_p(emid);

printf("parent:

pleaeenteratrfortetfile(trlen<80):

\n");

get(tr);

n=trlen(tr);

leek(fd,SEEK_SET,0);

write(fd,tr,n);

em_v(emid);

wait(0);

cloe(fd);

em_rmv(emid);

e某it(0);

}

}

思考题

1、参考程序中的em_p(),em_v()是原子操作吗?

这种模拟能达到预期效果吗?

它们与实验三中的lock()与unlock()有何异同?

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 互联网

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1