实验7  共享内存和信号量〔进程间通信〕
邢卫  2008-11-26修订
实验目的
学习并掌握Linux系统中的进程间通信机制,包括共享内存和信号量。
实验内容
1.学习共享内存相关的系统调用
shmget(), shmat(), shmdt, shmctl()
2.学习信号量〔semaphore〕相关的系统调用
semget(), semop(), semctl()
3.学习信号〔signal〕相关的系统调用
signal(), atexit()
4.完成?边干边学?第节的实验程序的编辑、编译、运行操作
5.分析、学习实验程序的工作过程和原理
6.选做:学习?边干边学?第6章,结合使用联机手册〔可以从man 2 ipc命令开始〕,编程练习各种进程间通信机制
实验步骤
1.以stu帐号登录
2.编辑程序
注意:在193页delete〔〕函数中,注意改成
if (mysemctl(Semid, 0, IPC_RMID, (union semun)0) == -1) {
限于实验的时间,该文件已预先存放在/home/stu/.kernel/lab6目录下,可以直接使用。但每位同学务必通读并理解该程序。
登录后,使用 cd .kernel/lab6 命令进入该文件所在目录,继续以下实验步骤。
3.编译 gcc reader_writer1.c -o reader_writer1
4.运行 ./reader_writer1
注意记录下共享内存的id号
5.使用 Alt+F2切换到第2个登录窗口,再次以stu帐号登录
可以使用who命令查看验证此时有两个stu用户已登录
可以使用ps l命令查看这两个stu用户的进程
6.在第2个stu用户窗口中,输入 ./reader_writer1 共享内存的id号
注意:此时,第2个stu用户窗口中的进程担当writer角,第1个stu用户窗口中的进程担当reader角。
7.在第2个窗口中,屡次输入信息;使用Alt+F1Alt+F2在两个窗口间切换,观察你对writer的输入,writer已经通过共享内存传递给了reader。
8.此时,你还可以使用Alt+F3切换到第3个登录窗口,并以stu帐号登录
可以使用who命令验证有3个stu用户登录;
可以经常性使用ps l命令来查看另外两个窗口中的进程的状态
9.切换到writer窗口〔第2个窗口〕,通过对writer的问题答复“2”,退出writer。切换到reader窗口〔第1个窗口〕,通过Ctrl+C终止reader进程。
思考题
1.同样的源程序,readerwriter进程是怎样各自到自己的定位的?
2.readerwriter是怎样通过信号量〔semphore〕实现同步的?writer是如何得知这一对信号量的id的?
3.数据是如何从writer传递到reader的?
4.writer是如何得知共享内存的id的?
5.在reader中,是如何捕获Ctrl-C信号〔signal〕的?捕获后是如何处理的?
6.一般来说,在Linux中使用共享内存〔shared memory〕的流程应该怎样?使用哪些系统调用?
7.一般来说,在Linux中使用信号量〔semaphore〕的流程应该怎样?使用哪些系统调用?
8.这里的共享内存,和使用带CLONE_VM标志的clone〔〕系统调用创立的两个task之间共享的内存,有什么异同?
参考资料
?边干边学?〔第1版〕第6章,“共享内存〞
具体源程序和实验操作详见节

附录1
共享内存的使用
共享内存共有4个系统调用:shmget,shmat,shmdt,shmctl
int shmget(key_t key, int size, int shmflg);
典型的创立共享内存的用法
shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | mode);
shmid = shmget(IPC_PRIVATE, size, mode);
void *shmat(int shmid, const void *shmaddr, int shmflg);
典型用法:
shmaddr = shmat(shmid, NULL, 0);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
典型用法:
取状态    shmctl(shmid, IPC_STAT, &buf);
删除    shmctl(shmid, IPC_RMID, NULL);
实例
struct shmid_ds buf;
shmid = shmget(key, size, flag);
if (shmid == -1) {
    // error handling ...
}
shmctl(shmid, IPC_STAT, &buf);
// 分析利用buf中的信息
shmaddr = (char *)shmat(id, NULL, 0);
if (shmaddr == -1) {
    // error handling ...
}
通过shmaddr使用共享内存的局部,如strcpy, sprintf, memcmp, 赋值操作,等等
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, NULL);

附录2 实验原理说明
本实验将建立一个利用共享内存来传递信息的程序,一个writer,一个readerwriter从用户处获得输入,然后将其写入共享内存,reader 从共享内存获取信息,然后再在屏幕上打印出
来。
利用共享内存在进程之间传递信息时,需要一种同步机制,必须有一种途径让reader知道什么时候writer已经把信息放入了共享内存。最简单的方法,是在某处设置一个字节,当writer的数据写入完毕后,即把该字节设置为1。但是这也意味着reader 必须不停地测试这个字节,直到该字节改变为止,这是非常浪费的。同样,对于writer 来说,也必须有一种途径知道什么时候reader 已经取走了共享内存的数据,从而可以向共享内存写入新的数据。因此,我们考虑用信号量〔semaphore〕来解决这个程序对于共享内存进行操作的同步问题,关于信号量的编程,请参考Linux man手册。
目前这个程序只支持两个进程,一个reader,一个writer。在稍后的时候,我们将改良这个程序使得其能够支持任意数目的进程。
在这个程序中,我们使用两个信号量,一个用于读〔SN_READ〕,一个用于写〔SN_WRITE〕。SN_READ初始化为1SN_WRITE初始化为0。即SN_READ这个信号量在最初的时候就是被锁住的,而SN_WRITE这个信号量那么不是。writer在往共享内存里写信息时,首先要锁定SN_WRITE信号量。在写完之后,释放SN_READ信号量,使得reader
可以读取该信息;锁定SN_WRITE这个信号量,是为了防止writer 屡次打印共享内存中的信息。reader读取共享内存的信息时,相应地要先锁定SN_READ这个信号量,读取信息后,释放SN_WRITE这个信号量,使得writer又可以往共享内存里面写入信息。
程序源代码参见reader。
编译:gcc reader_writer1.c –o reader_writer1
在此之后,即可启动reader。实验中必须先启动reader,因为使用的信号量、共享内存都是在reader中申请的。
在命令行输入:./reader_writer1
运行结果为:
reader begin to runand the id of share memory is 229376
wait for the writer’s
然后再启动writer,带的参数为reader 申请的共享内存的标识符。
在命令行输入:./reader_writer1 229376
运行结果为:
writer begin to runthe id of share memory is 229376, semaphore id is 196608
menu
1.send a message
input your choice1-2:1
wait for reader to read finish
please input information:
在提示后面输入:hello, reader
随即,reader 那边将打印这条信息。
然后循环往复。不再累赘。
关于退出:writer 可以通过菜单退出,reader 可以在writer 退出后,按Ctrl+C退出,退出reader时,它将自动删除最初申请信号量。
附录3  reader源程序
/**** reader_writer1.c  communicate through shared memory ****/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
进程间通信 共享内存#include <sys/shm.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
/* The union for semctl may or may not be defined for us.This code,defined in linux's semctl() manpage,is the proper way to attain it if necessary */
#if defined (__GNU_LIBRARY__)&& !defined (_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun{
    int val;            /* value for SETVAL */

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。