操作系统实验指导书
(2)IPC_SET。按buf指向的结构中的值,设置和改变有关消息队列属性的命令。如改变消息队列的用户标识符、消息队列的许可权等;
(3)IPC_RMID。消除消息队列的标识符。 msgqid_ds 结构定义如下: struct msgqid_ds
{ struct ipc_perm msg_perm; /*许可权结构*/ short pad1[7]; /*由系统使用*/ ushort msg_qnum; /*队列上消息数*/ ushort msg_qbytes; /*队列上最大字节数*/ ushort msg_lspid; /*最后发送消息的PID*/ ushort msg_lrpid; /*最后接收消息的PID*/ time_t msg_stime; time_t msg_rtime; time_t msg_ctime; };
struct ipc_perm
{ ushort uid; ushort gid; ushort cuid; ushort cgid; ushort mode; { short pid1; long pad2;} }
三、参考程序 1、client.c
#include
char mtext[1000]; }msg;
int msgqid;
void client() {
int i;
msgqid=msgget(MSGKEY,0777); for(i=10;i>=1;i--) {
msg.mtype=i;
printf(―(client)sent\\n‖);
msgsnd(msgqid,&msg,1024,0); }
exit(0); }
main( ) {
client( ); }
/*最后发送消息的时间*/ /*最后接收消息的时间*/ /*最后更改时间*/ /*当前用户*/ /*当前进程组*/ /*创建用户*/ /*创建进程组*/ /*存取许可权*/ /*由系统使用*/ /*打开75#消息队列*/ /*发送消息*/ 36
操作系统实验指导书
2、server.c
#include
char mtext[1000]; }msg;
int msgqid;
void server( ) {
msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*创建75#消息队列*/ do
{
msgrcv(msgqid,&msg,1030,0,0); /*接收消息*/ printf(―(server)received\\n‖); }while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0); /*删除消息队列,归还资源*/ exit(0); }
main( ) {
server( ); }
四、程序说明
1、为了便于操作和观察结果,编制二个程序client.c和server.c,分别用于消息的发送与接收。
2、server建立一个 Key 为75的消息队列,等待其它进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出server。server每接收到一个消息后显示一句“(server)received。”
3、client使用 key为75的消息队列,先后发送类型从10到1的消息,然后退出。最后一个消息,即是 server端需要的结束信号。client 每发送一条消息后显示一句 “(client)sent”。
4、注意: 二个程序分别编辑、编译为client与server。执行: ./server& ipcs -q ./client。
五、运行结果
从理想的结果来说,应当是每当client发送一个消息后,server接收该消息,client再发送下一条。也就是说“(client)sent”和 “(server)received‖的字样应该在屏幕上交替出现。实际的结果大多是,先由client发送了两条消息,然后server接收一条消息。此后client 、server交替发送和接收消息。最后server一次接收两条消息。client 和server 分别发送和接收了10条消息,与预期设想一致。
六、思考
message的传送和控制并不保证完全同步,当一个程序不在激活状态的时候,它完全可能继续睡眠,造成了上面的现象,在多次send message 后才recieve message。这一点有助于理解消息传送的实现机理。
37
操作系统实验指导书
实验三 进程通信 (三) 共享存储区通信
实验目的
了解和熟悉共享存储机制
实验内容
编制一长度为1k的共享存储区发送和接收的程序。
实验指导
一、共享存储区
1、共享存储区机制的概念
共享存储区(Share Memory)是UNIX系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区,每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信时,必须先在主存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其它部分的操作完全相同。进程之间便可通过对共享存储区中数据的读、写来进行直接通信。 应当指出,共享存储区机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信。
二、涉及的系统调用 1、shmget( )
创建、获得一个共享存储区。 系统调用格式:
shmid=shmget(key,size,flag)
该函数使用头文件如下:
#include
参数定义
int shmget(key,size,flag); key_t key; int size,flag;
其中,key是共享存储区的名字;size是其大小(以字节计);flag是用户设置的标志,如IPC_CREAT。IPC_CREAT表示若系统中尚无指名的共享存储区,则由核心建立一个共享存储区;若系统中已有共享存储区,便忽略IPC_CREAT。 附:
操作允许权 八进制数 用户可读 00400 用户可写 00200 小组可读 00040 小组可写 00020
38
操作系统实验指导书
其它可读 00004 其它可写 00002
控制命令 值 IPC_CREAT 0001000 IPC_EXCL 0002000 例:shmid=shmget(key,size,(IPC_CREAT|0400))
创建一个关键字为key,长度为size的共享存储区
2、shmat( )
共享存储区的附接。从逻辑上将一个共享存储区附接到进程的虚拟地址空间上。
系统调用格式:
virtaddr=shmat(shmid,addr,flag)
该函数使用头文件如下:
#include
参数定义
char *shmat(shmid,addr,flag); int shmid,flag; char * addr;
其中,shmid是共享存储区的标识符;addr是用户给定的,将共享存储区附接到进程的虚地址空间;flag规定共享存储区的读、写权限,以及系统是否应对用户规定的地址做舍入操作。其值为SHM_RDONLY时,表示只能读;其值为0时,表示可读、可写;其值为SHM_RND(取整)时,表示操作系统在必要时舍去这个地址。该系统调用的返回值是共享存储区所附接到的进程虚地址viraddr。
3、shmdt( )
把一个共享存储区从指定进程的虚地址空间断开。 系统调用格式:
shmdt(addr)
该函数使用头文件如下:
#include
参数定义
int shmdt(addr); char addr;
其中,addr是要断开连接的虚地址,亦即以前由连接的系统调用shmat( )所返回的虚地址。调用成功时,返回0值,调用不成功,返回-1。
4、shmctl( )
共享存储区的控制,对其状态信息进行读取和修改。 系统调用格式:
shmctl(shmid,cmd,buf)
该函数使用头文件如下:
#include
参数定义
int shmctl(shmid,cmd,buf); int shmid,cmd;
struct shmid_ds *buf;
其中,buf是用户缓冲区地址,cmd是操作命令。命令可分为多种类型:
39
操作系统实验指导书
(1)用于查询有关共享存储区的情况。如其长度、当前连接的进程数、共享区的创建者标识符等;
(2)用于设置或改变共享存储区的属性。如共享存储区的许可权、当前连接的进程计数等;
(3)对共享存储区的加锁和解锁命令; (4)删除共享存储区标识符等。
上述的查询是将shmid所指示的数据结构中的有关成员,放入所指示的缓冲区中;而设置是用由buf所指示的缓冲区内容来设置由shmid所指示的数据结构中的相应成员。
三、参考程序
#include
void client( ) { int i;
shmid=shmget(SHMKEY,1024,0777); /*打开共享存储区*/
addr=shmat(shmid,0,0); /*获得共享存储区首地址*/ for (i=9;i>=0;i--)
{ while (*addr!=-1);
printf(\ *addr=i; } exit(0); }
void server( ) {
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); /*创建共享存储区*/ addr=shmat(shmid,0,0); /*获取首地址*/ do {
*addr=-1;
while (*addr==-1);
printf(\}while (*addr);
shmctl(shmid,IPC_RMID,0); /*撤消共享存储区,归还资源*/ exit(0); }
main( ) {
while ((i=fork( ))= =-1); if (!i) server( );
system(―ipcs -m‖); while ((i=fork( ))= =-1); if (!i) client( ); wait(0); wait(0); }
四、程序说明
1、为了便于操作和观察结果,用一个程序作为“引子“,先后fork()两个子进程,server
40