1
进程实验3 Linux 进程间通信
一、 软中断信号的处理,实现同一用户的各进程之间的通信。
? 相关的系统调用
? kill(pid ,sig):发送信号 ? signal(sig, func):指定进程对信号sig的处理行为是调用函数func。 ? 程序清单
#include
kill(p1,16);
kill(p2,17); wait(0); wait(0); printf(\ exit(0); } else/* p2==0*/ { printf(\ wait_mark=1; signal(17,stop); waiting(); printf(\ exit(0); } } else/*p1==0*/ {
1
2
printf(\ wait_mark=1; signal(16,stop); waiting(); printf(\ exit(0); } }
void waiting()
{while(wait_mark!=0);} void stop()
{wait_mark=0;}
? 输入并运行此程序,分析程序的运行结果。
二、 消息的创建、发送和接收
? 多个进程通过访问一个公共的消息队列来交换信息 ? 消息队列:
即消息的一个链表
? 任何进程都可以向消息队列中发送消息(消息类型及正文),其它进程都可以从消息队列中根据类型获取相应的消息
? 相关的系统调用 头文件:#include
? 打开或创建消息队列:int msgget(key_t key, int msgflg);
? key:消息队列的键
? IPC_PRIVATE: 创建一个私有的消息队列 ? 其它:可被多个进程使用的消息队列
? msgflg:设置操作类型及访问权限IPC_CREAT / IPC_EXCL
? 获得或设置消息队列属性:int msgctl( int msgid, int cmd, struct msqid_ds
*data);
? 发送消息:int msgsnd(int msgid, const void *msgp,
size_t msgsize, int flags); ? 参数
? msgid:消息队列标识符id
? msgp:指针,用户自定义缓冲区,可定义成结构体类型,包含两项
long mtype;代表消息类型
char mtext[MTEXTSIZE];消息正文 ? msgsize:要发送消息正文的长度
? mflags:标志,若设置IPC_NOWAIT则不等待
消息发出就返回
? 返回值:成功返回0,错误返回-1(置errno)
? 接收消息int msgrcv(int msgid, void *msgp, size_t mtexsize, long msgtype,
int flags);
2
3
? 参数:与msgsnd类似
? msgtype
? >0:只接收指定类型消息的第一个
? ==0:不管什么消息类型都读取队列中第一个数据
? <0:接收等于或小于其绝对值的最低类型的第一个,如有5、
6、17三类,若为-6,则获取类型5的。
? 返回值
? 成功:返回消息正文字节数 ? 错误:返回-1(置errno)
? 程序清单
#include
long mtype;
char msgtext[1030]; }msg;
int msgqid,i; void CLIENT() {
int i; char string_i[5];
msgqid=msgget(MSGKEY,0777); for(i=10;i>=1;i--) {
msg.mtype=i;
printf(\
sprintf(msg.msgtext,\ message \ sprintf(string_i, \ strcat(msg.msgtext,string_i); strcat(msg.msgtext,\
msgsnd(msgqid,&msg,1030,0); }
exit(0); }
void SERVER() {
msgqid=msgget(MSGKEY,0777|IPC_CREAT); do { msgrcv(msgqid,&msg,1030,0,0); printf(\
3
4
printf(“%s\\n\ }while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0); exit(0); }
main() {
while((i=fork())==-1); if(!i) SERVER();
while((i=fork())==-1); if(!i) CLIENT(); wait(0); wait(0); }
编辑并运行程序,并分析程序的运行结果。 思考题:符号常量MSGKEY有什么作用?server和client不使用同一个MSGKEY会出现什么问题?
程序扩展:client和server之间怎样通过软中断信号控制进程的推进速度,使得client每发送一个消息,server就接收一个消息,然后client再发送下一个消息?
三、 共享存储区的创建、发送和接收
同一系统中的几个进程可共享某块物理内存。include
? 打开或创建创建共享区:int shmget(key_t key, size_t size, int shmflg);
? 参数
? key:键值 ? IPC_PRIVATE: 创建一个私有的shm ? 其它:非IPC_PRIVATE整数值。 ? size:指明shm的大小,若shm已经存在,则size应为0 ? shmflg:设置访问权限及IPC_CREAT / IPC_EXCL ? 返回值
? 成功:该shm的id,当前进程是其 拥有者及创建者
错误:-1
? 将共享内存连接到进程中:void *shmat(int shmid, const void *shmaddr, int flags);
? 参数
? shmid:共享内存标识符id ? shmaddr:进程映射内存段的地址,可指定,但一般设为NULL表示
由系统安排。 ? flags:对该内存的段设置是否只读 (SHM_RDONLY),
默认是读写。
? 返回值
? 成功:进程中该内存段的地址 ? 错误: -1
4
? 程序清单:
#include
int shmid,i; int *addr;
void CLIENT() {
int i;
shmid=shmget(SHMKEY,1024,0777); addr=shmat(shmid,0,0); for(i=5;i>=0;i--) { while(*addr!=-1); printf(\ *addr=i;
printf(\ }
exit(0); }
void SERVER() {
shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); addr=shmat(shmid,0,0); do { *addr=-1; while(*addr==-1); printf(\ printf(\ }while(*addr);
shmctl(shmid,IPC_RMID,0); exit(0); }
main()
5
5
6
{
while((i=fork())==-1); if(!i)SERVER();
while((i=fork())==-1); if(!i) CLIENT(); wait(0); wait(0); }
编辑并运行程序,并分析程序的运行结果。
在此基础上对程序进行修改:使得每次循环中:CLIENT向共享区发送10个整数, SERVER从共享区接收10个整数、并输出。
6