进程实验3 Linux 进程间通信
一、 软中断信号的处理,实现同一用户的各进程之间的通信。
相关的系统调用
kill(pid ,sig):发送信号
signal(sig, func):指定进程对信号sig的处理行为是调用函数func。
程序清单
#include #include #include void waiting(); void stop(); int wait_mark; main() 1 2 { int p1,p2; while((p1=fork())==-1); if(p1>0) { while((p2=fork())==-1); if(p2>0) { printf(\"parent\\n\"); /*父进程在此完成某个操作、或接收到用户从键盘输入的特殊按键命令后发出下面的信号。这里省略。 */ kill(p1,16); kill(p2,17); wait(0); wait(0); 2 printf(\"parent process id killed! \\n\"); exit(0); } else/* p2==0*/ { printf(\"p2\\n\"); wait_mark=1; signal(17,stop); waiting(); printf(\"child process 2 is killed by parent! \\n\"); exit(0); } } 3 3 else/*p1==0*/ { printf(\"p1\\n\"); wait_mark=1; signal(16,stop); waiting(); printf(\"child process 1 is kelled by parent! \\n\"); exit(0); } } void waiting() {while(wait_mark!=0);} void stop() 4 4 5 {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 5 msqid_ds *data); 发送消息:int msgsnd(int msgid, const void *msgp, size_t msgsize, int flags); 参数 msgid:消息队列标识符id msgp:指针,用户自定义缓冲区,可定义成结构体类型,包含两项 mtype;代表消息类型 char mtext[MTEXTSIZE];消息正文 msgsize:要发送消息正文的长度 mflags:标志,若设置IPC_NOWAIT则不等待 息发出就返回 返回值:成功返回0,错误返回-1(置errno) 接收消息int msgrcv(int msgid, void *msgp, size_t mtexsize, msgtype, int flags); 参数:与msgsnd类似 6 long 消 long 6 7 msgtype >0:只接收指定类型消息的第一个 ==0:不管什么消息类型都读取队列中第一个数据 <0:接收等于或小于其绝对值的最低类型的第一个,如有5、17三类,若为-6,则获取类型5的。 返回值 成功:返回消息正文字节数 错误:返回-1(置errno) 程序清单 #include #include #include #include #define MSGKEY 75 6、 7 struct msgform { 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; 8 8 printf(\"(client)sent\\n\"); sprintf(msg.msgtext,\"the content of message \"); sprintf(string_i, \"%d\ strcat(msg.msgtext,string_i); strcat(msg.msgtext,\"\\n\"); msgsnd(msgqid,&msg,1030,0); } exit(0); } void SERVER() { msgqid=msgget(MSGKEY,0777|IPC_CREAT); do 9 9 { msgrcv(msgqid,&msg,1030,0,0); printf(\"(server)received message %d \\n\ 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); 10 10 11 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:键值 11 12 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), 默认是读 写。 12 返回值 成功:进程中该内存段的地址 错误: -1 程序清单: #include #include #include #include #define SHMKEY 75 int shmid,i; int *addr; void CLIENT() { 13 13 int i; shmid=shmget(SHMKEY,1024,0777); addr=shmat(shmid,0,0); for(i=5;i>=0;i--) { while(*addr!=-1); printf(\"(client)sent, \"); *addr=i; printf(\"client i: %d\\n\ } exit(0); } void SERVER() 14 14 { shmid=shmget(SHMKEY,1024,0777|IPC_CREAT); addr=shmat(shmid,0,0); do { *addr=-1; while(*addr==-1); printf(\"(server)received ,\" ); printf(\"server *addr %d\\n\ }while(*addr); shmctl(shmid,IPC_RMID,0); exit(0); } 15 15 16 main() { while((i=fork())==-1); if(!i)SERVER(); while((i=fork())==-1); if(!i) CLIENT(); wait(0); wait(0); } 编辑并运行程序,并分析程序的运行结果。 在此基础上对程序进行修改:使得每次循环中:CLIENT向共享区发送10个整数, SERVER从共享区接收10个整数、并输出。 16 因篇幅问题不能全部显示,请点此查看更多更全内容