实验三补充资料Word文档下载推荐.docx
- 文档编号:20266424
- 上传时间:2023-01-21
- 格式:DOCX
- 页数:18
- 大小:33.58KB
实验三补充资料Word文档下载推荐.docx
《实验三补充资料Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《实验三补充资料Word文档下载推荐.docx(18页珍藏版)》请在冰豆网上搜索。
create_shm.c使用shmget函数include<
sys/types.h>
sys/ipc.h>
stdlib.h>
stdio.h>
#defineBUFSZ4096
intmain(void)
{
intshm_id;
/*共享内存标识符*/
shm_id=shmget(IPC_PRIVATE,BUFSZ,0666);
if(shm_id<
0){
/*创建共享内存*/
perror("
shmget"
);
exit
(1);
}
printf("
successfullycreatedsegment:
%d\n"
shm_id);
system("
ipcs-m"
);
/*调用ipcs命令查看IPC*/
exit(0);
}
(2)在shell中编译该程序如下:
$gcccreate_shm.c-ocreate_shm
(3)在shell中运行该程序如下:
$./create_shm
2752516
------SharedMemorySegments--------
key
shmid
owner
perms
bytes
nattch
status
0x0000000065536
root
600
393216
2
dest
0x000000002654209
666
4096
0
0x0056a4d52686978
488
1
0x0056a4d62719747
131072
0x000000002752516
上述程序中使用shmget函数来创建一段共享内存,并在结束前调用了系统shell命令ipcs-m来查看当前系统IPC状态。
2.共享内存的操作
由于共享内存这一特殊的资源类型,使它不同于普通的文件,因此,系统需要为其提供专有的操作函数,而这无疑增加了程序员开发的难度(需要记忆额外的专有函数)。
使用函数shmctl可以对共享内存段进行多种操作,其函数原型如下:
intshmctl(intshm_id,intcmd,structshmid_ds*buf);
函数中参数sh_mid为所要操作的共享内存段的标识符,structshmid_ds型指针参数buf的作用与参数cmd的值相关,参数cmd指明了所要进行的操作,其解释如表2所示。
表2
shmctl函数中参数cmd详解
cmd的值
意义
IPC_STAT
取shm_id所指向内存共享段的shmid_ds
结构,对参数buf指向的结构赋值
IPC_SET
使用buf指向的结构对sh_mid段的相关结
构赋值,只对以下几个域有作用,shm_perm.
uidshm_perm.gid以及shm_perm.mode
注意此命令只有具备以下条件的进程才可以请求:
1.进程的用户ID等于shm_perm.cuid或者
等于shm_perm.uid
2.超级用户特权进程
IPC_RMID
删除shm_id所指向的共享内存段,只有当
shmid_ds结构的shm_nattch域为零时,才
会真正执行删除命令,否则不会删除该段
注意此命令的请求规则与IPC_SET命令相同
SHM_LOCK
锁定共享内存段在内存,此命令只能由超级用户请求
SHM_UNLOCK
对共享内存段解锁,此命令只能由超级用户请求
使用函数shmat将一个存在的共享内存段连接到本进程空间,其函数原型如下:
void*shmat(intshm_id,constvoid*addr,intflag);
函数中参数shm_id指定要引入的共享内存,参数addr与flag组合说明要引入的地址值,通常只有2种用法,addr为0,表明让内核来决定第1个可以引入的位置。
addr非零,并且flag中指定SHM_RND,则此段引入到addr所指向的位置(此操作不推荐使用,因为不会只对一种硬件上运行应用程序,为了程序的通用性推荐使用第1种方法),在flag参数中可以指定要引入的方式(读写方式指定)。
说明:
函数成功执行返回值为实际引入的地址,失败返回-1。
shmat函数成功执行会将shm_id段的shmid_ds结构的shm_nattch计数器的值加1。
当对共享内存段操作结束时,应调用shmdt函数,作用是将指定的共享内存段从当前进程空间中脱离出去。
intshmdt(void*addr);
参数addr是调用shmat函数的返回值,函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,失败返回-1。
下面实例演示了操作共享内存段的流程。
程序的开始部分先检测用户是否有输入,如出错则打印该命令的使用帮助。
接下来从命令行读取将要引入的共享内存ID,使用shmat函数引入该共享内存,并在分离该内存之前睡眠3秒以方便查看系统IPC状态。
程序清单2
opr_shm.c操作共享内存段
intmain(intargc,char*argv[])
intshm_id;
char*shm_buf;
if(argc!
=2){/*命令行参数错误*/
USAGE:
atshm<
identifier>
"
);
/*打印帮助消息*/
exit
(1);
shm_id=atoi(argv[1]);
/*得到要引入的共享内存段*/
/*引入共享内存段,由内核选择要引入的位置*/
if((shm_buf=shmat(shm_id,0,0))<
(char*)0){
perror("
shmat"
exit
(1);
segmentattachedat%p\n"
shm_buf);
/*输出导入的位置*/
system("
sleep(3);
/*休眠*/
if((shmdt(shm_buf))<
/*与导入的共享内存段分离*/
shmdt"
exit
(1);
segmentdetached\n"
system("
ipcs-m"
/*再次查看系统IPC状态*/
exit(0);
$gccopr_shm.c-oopr_shm
$./opr_shm2752516
segmentattachedat0xb7f29000
segmentdetached
上述程序中从命令行中读取所要引入的共享内存ID,并使用shmat函数引入该内存到当前的进程空间中。
注意在使用shmat函数时,将参数addr的值设为0,所表达的意义是由内核来决定该共享内存在当前进程中的位置。
由于在编程的过程中,很少会针对某一个特定的硬件或系统编程,所以由内核决定引入位置也就是shmat推荐的使用方式。
在导入后使用shell命令ipcs-m来显示当前的系统IPC的状态,可以看出输出信息中nattch字段为该共享内存时的引用值,最后使用shmdt函数分离该共享内存并打印系统IPC的状态。
3.共享内存使用注意事项
共享内存相比其他几种方式有着更方便的数据控制能力,数据在读写过程中会更透明。
当成功导入一块共享内存后,它只是相当于一个字符串指针来指向一块内存,在当前进程下用户可以随意的访问。
缺点是,数据写入进程或数据读出进程中,需要附加的数据结构控制,共享内存通信数据结构示意如图1所示。
图1共享内存通信数据结构示意
图中两个进程同时遵循一定的规则来读写该内存。
同时,在多进程同步或互斥上也需要附加的代码来辅助共享内存机制。
在共享内存段中都是以字符串的默认结束符为一条信息的结尾。
每个进程在读写时都遵守这个规则,就不会破坏数据的完整性。
基于消息队列机制通信
1.创建消息队列
消息队列是三个IPC对象类型中最具有数据操作性的数据传送方式,在消息队列中可以随意根据特定的数据类型值来检索消息。
当然,其缺点也显而易见,为了维护该数据链表,就需要更多的内存资源,而且在数据读写上比起共享内存也更复杂一些,时间开销也更大一些。
函数msgget可以创建或打开一个队列,函数原型如下:
#include
intmsgget(key_tkey,intflags);
函数中参数key用来转换成一个标识符,每一个IPC对象与一个key相对应。
参数flags标明函数的行为。
下面实例演示了使用msgget函数创建一个队列,函数中参数falgs指定为IPC_CREAT|0666,说明新建一个权限为0666的消息队列,其中组用户、当前用户以及其他用户拥有读写的权限。
并在程序的最后使用shell命令ipcs-q来查看系统IPC的状态。
程序清单3
create_msg.cmsgget函数
intmain(void)
int
qid;
key_t
key;
key=113;
qid=msgget(key,IPC_CREAT|0666);
/*创建一个消息队列*/
if(qid<
/*创建一个消息队列失败*/
msgget"
exit
(1);
printf("
createdqueueid:
qid);
/*输出消息队列的ID*/
ipcs-q"
/*查看系统IPC的状态*/
$gcccreate_msg.c-ocreate_msg
$./create_msg
------MessageQueues--------
msqid
used-bytes
messages
0x0000af40623430
0
0x0000007b0
在程序中使用了系统命令ipcs,命令参数-q说明只查看消息队列的状态。
注意在输出消息中,key段标明的是IPC的key值,msqid为该队列的ID值,perms为执行权限。
同样,队列的执行权限像其他IPC对象一样没有执行权限。
函数msgctl可以在队列上做多种操作,函数原型如下:
intmsgctl(intmsqid,intcmd,structmsqid_ds*buf);
参数msqid为指定的要操作的队列,cmd参数指定所要进行的操作,其中有些操作需要buf参数。
cmd参数的详细取值及操作如表3所示。
表3
cmd参数详解
cmd
操作
取队列的msqid_ds结构,将它存放在buf所指
向的结构中(需要buf参数)
使用buf所指向结构中的值对当前队列的相关
结构成员赋值,其中包括:
msg_perm.uid、
msg_perm.gid、msg_perm.mode以及msg_perm.cuid。
该命令只能由具有以下条件的进程执行:
进程有效用
户ID等于msg_perm.cuid或msg_perm.uid超级用户进程。
其中只有超级用户才可以增加队列的msg_qbytes的值
删除队列,并清除队列中的所有消息。
此操作会影响后
续进程对这个队列的相关操作。
该命令只能由具有以下
条件的进程执行。
进程有效用户ID等于msg_perm.cuid
或msg_perm.uid,超级用户进程
下面实例演示了调用msgctl函数操作队列,程序中先读取命令行参数,如没有,则打印命令提示信息,在调用msgctl函数执行删除操作的前后分别调用了一次shell命令ipcs-q来查看系统IPC的状态。
程序清单4del_msg.c调用msgctl删除指定队列
intmain(intargc,char*argv[])
intqid;
=2){/*命令行参数出错*/
puts("
del_msgq.c"
qid=atoi(argv[1]);
/*通过命令行参数得到组ID*/
if((msgctl(qid,IPC_RMID,NULL))<
0){/*删除指定的消息队列*/
perror("
msgctl"
successfullyremoved%d
queue\n"
/*删除队列成功*/
$gccdel_msg.c-odel_msg
$./del_msg
successfullyremoved0
queue
2.读写消息队列
(1)
由于消息队列的特殊性,系统为这个数据类型提供了两个接口(msgsnd函数,msgrcv函数),分别对应写消息队列及读消息队列。
将一个新的消息写入队列,使用函数msgsnd,函数原型如下:
intmsgsnd(intmsqid,constvoid*prt,size_tnbytes,intflags);
对于写入队列的每一个消息,都含有三个值,正长整型的类型字段、数据长度字段和实际数据字节。
新的消息总是放在队列的尾部,函数中参数msqid指定要操作的队列,ptr指针指向一个msgbuf的结构,定义如下:
structmsgbuf{
longmtype;
charmbuf[];
};
这是一个模板的消息结构,其中成员mbuf是一个字符数组,长度是根据具体的消息来决定的,切忌消息不能以NULL结尾。
成员mtype是消息的类型字段。
函数参数nbytes指定了消息的长度,参数flags指明函数的行为。
函数成功返回0,失败返回-1并设置错误变量errno。
errno可能出现的值有:
EAGAIN、EACCES、EFAULT、EIDRM、EINTR、EINVAL和ENOMEM。
当函数成功返回后会更新相应队列的msqid_ds结构。
使用函数msgrcv可以从队列中读取消息,函数原型如下:
ssize_tmsgrcv(intmsqid,void*ptr,size_tnbytes,longtype,intflag);
函数中参数msqid为指定要读的队列,参数ptr为要接收数据的缓冲区,nbytes为要接收数据的长度,当队列中满足条件的消息长度大于nbytes的值时,则会参照行为参数flag的值决定如何操作:
当flag中设置了MSG_NOERROR位时,则将消息截短到nbytes指定的长度后返回。
如没有MSG_NOERROR位,则函数出错返回,并设置错误变量errno。
设置type参数指定msgrcv函数所要读取的消息,tyre的取值及相应操作如表4所示。
表4
type值详解
type
等于0
返回队列最上面的消息(根据先进先出规则)
大于0
返回消息类型与type相等的第1条消息
小于0
返回消息类型小于等于type绝对值的最小值的第1条消息
参数flag定义函数的行为,如设置了IPC_NOWAIT位,则当队列中无符合条件的消息时,函数出错返回,errno的值为ENOMSG。
如没有设置IPC_NOWAIT位,则进程阻塞直到出现满足条件的消息出现为止,然后函数读取消息返回。
下面实例演示了消息队列在进程间的通信。
程序中创建了一个消息的模板结构体,并对声明变量做初始化。
使用msgget函数创建了一个消息队列,使用msgsnd函数向该队列中发送了一条消息。
程序清单5
snd_msg.c调用msgsnd函数向队列中发送消息
structmsg{
/*声明消息结构体*/
longmsg_types;
/*消息类型成员*/
charmsg_buf[511];
/*消息*/
intmain(void){
int
pid;
len;
structmsgpmsg;
/*一个消息的结构体变量*/
pmsg.msg_t
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 补充 资料