lab9进程的通信–消息队列

一.两个进程并发执行,通过消息队列,分别进行消息的发送和接收

1.代码:

//接受消息
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>struct my_msg_st{long int my_msg_type;char some_text[BUFSIZ];
}; int main(){int running=1;int msgid;struct my_msg_st some_data;long int msg_to_receive=0;//First,we set up thee message queuemsgid=msgget((key_t)1234,0666|IPC_CREAT);if(msgid==-1){fprintf(stderr,"megget failed with error: %d\n",errno);exit(EXIT_FAILURE);}//Then the message are retrieved from the queue,until an end message is encountered
//Lastly,the message queue id deletedwhile(running){if(msgrcv(msgid,(void*)&some_data,BUFSIZ,msg_to_receive,0)==-1){fprintf(stderr,"msgrcv failed with error: %d\n",errno);exit(EXIT_FAILURE);}printf("You wrote: %s ",some_data.some_text);if(strncmp(some_data.some_text,"end",3)==0)running=0;}if(msgctl(msgid,IPC_RMID,0)==-1){fprintf(stderr,"msgctl(IPC_RMID) failed\n");exit(EXIT_FAILURE);}exit(EXIT_SUCCESS);
}
///发送消息
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>#define MAX_TEXT 512
struct my_msg_st{long int my_msg_type;char some_text[MAX_TEXT];
}; int main(){int running=1;int msgid;struct my_msg_st some_data;char buffer[BUFSIZ];msgid=msgget((key_t)1234,0666|IPC_CREAT);if(msgid==-1){fprintf(stderr,"megget failed with error: %d\n",errno);exit(EXIT_FAILURE);}while(running){printf("Enter some text:");fgets(buffer,BUFSIZ,stdin);some_data.my_msg_type=1;strcpy(some_data.some_text,buffer);if(msgsnd(msgid,(void*)&some_data,MAX_TEXT,0)==-1){fprintf(stderr,"msgsnd failed\n");exit(EXIT_FAILURE);}if(strncmp(buffer,"end",3)==0)running=0;}exit(EXIT_SUCCESS);
}
//开两个终端分别运行

执行结果如图:

2)熟悉消息队列相关的系统调用

1.头文件:  #include<sys/msg.h>#include<sys/types.h>#include<sys/ipc.h>
2.操作:创建队列:       msgget((key_t)10086,0666|IPC_CREAT);发送信息:        msgsnd(mq,(void*)&over2,MAX_SIZE,0)接收信息:     msgrcv(mq,(void*)&buf,1024,0,0)指定操作:     msgctl(mq,IPC_RMID,&t)

3)尝试多个发送进程和接收进程,观察进程的并发执行情况,并解释

现象:多个发送信息的终端在输入后,信息依次轮序出现在各个接收端进程中
解释:消息队列(MQ)由内核提供同步,互斥机制,可以翻阅msgsnd,msgrcv linux底层源代码一探究竟

链接

如图:



二.三个线程(两个发送者,一个接收者)并发执行。通过消息队列,分别进行消息的发送和接收

1.代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<errno.h>
#include<semaphore.h>
#include<sys/stat.h>
#include<sys/msg.h>#define QUEUE_ID 10086
#define MAX_SIZE 1024
#define MSG_STOP "exit"
#define snd_to_rcv1 1
#define snd_to_rcv2 2
#define rcv_to_snd1 3
#define rcv_to_snd2 4
#define CHECK(x) \do{\if(!(x)){\fprintf(stderr,"%s:%d:",__func__,__LINE__);\perror(#x);\exit(-1);\}\}while(0)\#define P(x) sem_wait(&x)
#define V(x) sem_post(&x)struct msg_st{                 //long int message_type;char buffer[MAX_SIZE+1];
};//function
void *sender1();
void *sender2();
void *receiver();//global variable
sem_t w_mutex,empty,full,over,rcv_dp,snd_dp;void *sender1(){int mq;struct msg_st buf;ssize_t bytes_read;//open the mail queuemq=msgget((key_t)QUEUE_ID,0666|IPC_CREAT);CHECK((key_t)-1!=mq);do{           P(w_mutex);
//              printf("11\n");P(snd_dp);
//              printf("12\n");printf("sender1>");V(rcv_dp);fflush(stdout);fgets(buf.buffer,BUFSIZ,stdin);buf.message_type=1;//send the messageP(empty);
//              printf("13\n");CHECK(0<=msgsnd(mq,(void*)&buf,MAX_SIZE,0));V(full);V(w_mutex);usleep(100);}while(strncmp(buf.buffer,MSG_STOP,strlen(MSG_STOP)));//wait for responseP(over);
//              printf("14\n");bytes_read=msgrcv(mq,(void*)&buf,MAX_SIZE,rcv_to_snd1,0);CHECK(bytes_read>=0);printf("%s",buf.buffer);printf("--------------------------\n");V(snd_dp);pthread_exit(NULL);
}
void *sender2(){int mq;struct msg_st buf;ssize_t bytes_read;//open the mail queuemq=msgget((key_t)QUEUE_ID,0666|IPC_CREAT);CHECK((key_t)-1!=mq);do{P(w_mutex);
//              printf("21\n");P(snd_dp);
//              printf("22\n");printf("sender2>");V(rcv_dp);fflush(stdout);fgets(buf.buffer,BUFSIZ,stdin);buf.message_type=2;//send the messageP(empty);
//              printf("23\n");CHECK(0<=msgsnd(mq,(void*)&buf,MAX_SIZE,0));V(full);V(w_mutex);usleep(100);}while(strncmp(buf.buffer,MSG_STOP,strlen(MSG_STOP)));//wait for responseP(over);
//              printf("24\n");bytes_read=msgrcv(mq,(void*)&buf,MAX_SIZE,rcv_to_snd2,0);CHECK(bytes_read>=0);                                //printf("%s",buf.buffer);printf("--------------------------\n");V(snd_dp);pthread_exit(NULL);
}
void *receiver(){struct msg_st buf,over1,over2;int mq,must_stop=2;struct msqid_ds t;over1.message_type=3;strcpy(over1.buffer,"over1\n");over2.message_type=4;strcpy(over2.buffer,"over2\n");//open the mail queuemq=msgget((key_t)QUEUE_ID,0666|IPC_CREAT);CHECK((key_t)-1!=mq);do{ssize_t bytes_read,bytes_write;//receive the messageP(full);
//              printf("31\n");           bytes_read=msgrcv(mq,(void*)&buf,MAX_SIZE,0,0);V(empty);CHECK(bytes_read>=0);if(!strncmp(buf.buffer,MSG_STOP,strlen(MSG_STOP))){if(buf.message_type==1){
//                  printf("321\n");                      bytes_write=msgsnd(mq,(void*)&over1,MAX_SIZE,0);CHECK(bytes_write>=0);V(over);must_stop--;}else if(buf.message_type==2){
//                  printf("322\n");                      bytes_write=msgsnd(mq,(void*)&over2,MAX_SIZE,0);       //CHECK(bytes_write>=0);V(over);must_stop--;}else{
//                  printf("323\n");          P(rcv_dp);printf("Received %d:%s",buf.message_type,buf.buffer);printf("------------------------------------------\n");V(snd_dp); }}}while(must_stop);//clean upP(snd_dp);
//              printf("33/n");CHECK(!msgctl(mq,IPC_RMID,&t));        //pthread_exit(NULL);
}int main(int argc,char **argv){pthread_t t1,t2,t3;int state;sem_init(&snd_dp,1,1);sem_init(&rcv_dp,1,0);sem_init(&empty,1,10);sem_init(&full,1,0);sem_init(&w_mutex,1,1);sem_init(&over,1,0);state=pthread_create(&t1,NULL,receiver,NULL);CHECK(state==0);state=pthread_create(&t3,NULL,sender1,NULL);CHECK(state==0);state=pthread_create(&t2,NULL,sender2,NULL);CHECK(state==0);pthread_join(t3,NULL);pthread_join(t2,NULL);pthread_join(t1,NULL);return 0;
}
注意:运行后,两次均输入exit,才能满足receive解锁条件,实现同步

运行如图:

2)熟悉消息队列相关的系统调用

1.头文件:     #include<sys/msg.h>#include<sys/types.h>#include<sys/ipc.h>
2.操作:创建队列:       msgget((key_t)10086,0666|IPC_CREAT);发送信息:        msgsnd(mq,(void*)&over2,MAX_SIZE,0)接收信息:     msgrcv(mq,(void*)&buf,1024,0,0)指定操作:     msgctl(mq,IPC_RMID,&t)

3)回顾posix线程控制和信号量相关的函数

1.头文件: #include<semaphore.h>
2.操作:声明:    sem_t sem1初始:    sem_init(&sem1,1,1)p操作:   sem_wait(&sem1)v操作:   sem_post(&sem1)
3.互斥/同步: pv/vp

4)删除信号量的并发控制,观察混乱情况

代码中注释掉所有P操作

5)理清并发线程中同步和互斥关系

1.操作:去掉原文代码所有注释       作用:在所有P操作后进行输出,来观察进程并发执行情况

运行如图:

流程图:并发线程同步,互斥关系:(sender1与sender2互斥)
左边流程图与右边程序结合一起看哦
欢迎访问gitee仓库:ZUCC_操作系统原理实验_Lab9进程的通信消息队列



三.编写程序

修改例程1,模仿例程2,在原有的MSG1向MSG2发送消息的基础上,实现MSG2也能向MSG1发送消息,即两并发进程能通过消息队列,实现双向对话。

1.构造核心:

 1.使用System V信号量实现两个进程间的通信2.使用消息队列实现两个进程间消息的接收与发送3.确定流程图顺序,从而确定信号量个数与初值的设定,同时流程图拆分确定两个进程的PV操作和核心代码

2.sender,receiver进程并发控制的流程图及代码构成

3.代码:

///发送消息
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<fcntl.h>
#include<sys/sem.h>
#include<sys/stat.h>struct my_msg_st{long int my_msg_type;char some_text[BUFSIZ];
};
union semun{int val;                //value for setvalstruct semid_ds *buf; //buffer for IPC_STAT,IPC_SETunsigned short int *array; //array for GETALL,SETALLstruct seminfo *_buf;  //buffer for IPC_INFO
};static int sem_id=0;
static int set_semvalue(int semnum,int sem_value);
static void del_semvalue(int semnum);
static int semaphore_p(int semnum);
static int semaphore_v(int semnum);int main(){int running=1;int msgid;struct my_msg_st some_data;char buffer[BUFSIZ];msgid=msgget((key_t)1234,0666|IPC_CREAT);sem_id=semget((key_t)1234,4,0666|IPC_CREAT);       //创建信号量         //会与msgget冲突吗? set_semvalue(0,0);set_semvalue(1,0);set_semvalue(2,0);set_semvalue(3,0);while(running){//输入发送printf("Enter some text:");fgets(buffer,BUFSIZ,stdin);some_data.my_msg_type=1;strcpy(some_data.some_text,buffer);msgsnd(msgid,(void*)&some_data,BUFSIZ,0);semaphore_v(0);if(strncmp(some_data.some_text,"end",3)==0)break;semaphore_p(1);//接收输出msgrcv(msgid,(void*)&some_data,BUFSIZ,0,0);printf("You wrote: %s",some_data.some_text);semaphore_v(2);if(strncmp(some_data.some_text,"end",3)==0)break;semaphore_p(3);//接收输出msgrcv(msgid,(void*)&some_data,BUFSIZ,0,0);printf("You wrote: %s",some_data.some_text);if(strncmp(some_data.some_text,"end",3)==0)break;        }exit(EXIT_SUCCESS);
}
//开两个终端分别运行static int set_semvalue(int semnum,int sem_value){           //初始化信号量,使用信号量前必须这样做 union semun sem_union;sem_union.val=sem_value;if(semctl(sem_id,semnum,SETVAL,sem_union)==-1){fprintf(stderr,"Failed to set the semaphore\n");return 0;}return 1;
}
static void del_semvalue(int semnum){           //删除信号量 union semun sem_union;if(semctl(sem_id,semnum,IPC_RMID,sem_union)==-1){fprintf(stderr,"Failed to delete the semaphore\n");}
}
static int semaphore_p(int semnum){         //对信号量做-1,即等待P struct sembuf sem_b;sem_b.sem_num=semnum;sem_b.sem_op=-1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){fprintf(stderr,"semaphore_p failed\n");return 0;}return 1;
}
static int semaphore_v(int semnum){     //释放操作,使得信号量可用,发送V信号 struct sembuf sem_b;sem_b.sem_num=semnum;sem_b.sem_op=1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){fprintf(stderr,"semaphore_v failed\n");return 0;}return 1;
}
//接受消息
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/sem.h>union semun{int val;               //value for setvalstruct semid_ds *buf; //buffer for IPC_STAT,IPC_SETunsigned short int *array; //array for GETALL,SETALLstruct seminfo *_buf;  //buffer for IPC_INFO
};static int sem_id=0;
static int set_semvalue(int semnum,int sem_value);
static void del_semvalue(int semnum);
static int semaphore_p(int semnum);
static int semaphore_v(int semnum);struct my_msg_st{long int my_msg_type;char some_text[BUFSIZ];
}; int main(){int running=1;int msgid;struct my_msg_st some_data;char buffer[BUFSIZ];msgid=msgget((key_t)1234,0666|IPC_CREAT);sem_id=semget((key_t)1234,4,0666|IPC_CREAT);       //创建信号量         //会与msgget冲突吗? while(running){semaphore_p(0);//接收输出msgrcv(msgid,(void*)&some_data,BUFSIZ,0,0);printf("You wrote: %s",some_data.some_text);if(strncmp(some_data.some_text,"end",3)==0)break;//输入发送printf("Enter some text:");fgets(buffer,BUFSIZ,stdin);some_data.my_msg_type=1;strcpy(some_data.some_text,buffer);msgsnd(msgid,(void*)&some_data,BUFSIZ,0);semaphore_v(1);if(strncmp(some_data.some_text,"end",3)==0)break;semaphore_p(2);//输入发送printf("Enter some text:");fgets(buffer,BUFSIZ,stdin);some_data.my_msg_type=1;strcpy(some_data.some_text,buffer);msgsnd(msgid,(void*)&some_data,BUFSIZ,0);semaphore_v(3);    if(strncmp(some_data.some_text,"end",3)==0)break;}sleep(1);msgctl(msgid,IPC_RMID,0);del_semvalue(0); exit(EXIT_SUCCESS);
}static int set_semvalue(int semnum,int sem_value){         //初始化信号量,使用信号量前必须这样做 union semun sem_union;sem_union.val=sem_value;if(semctl(sem_id,semnum,SETVAL,sem_union)==-1){fprintf(stderr,"Failed to set the semaphore\n");return 0;}return 1;
}
static void del_semvalue(int semnum){           //删除信号量 union semun sem_union;if(semctl(sem_id,semnum,IPC_RMID,sem_union)==-1){fprintf(stderr,"Failed to delete the semaphore\n");}
}
static int semaphore_p(int semnum){         //对信号量做-1,即等待P struct sembuf sem_b;sem_b.sem_num=semnum;sem_b.sem_op=-1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){fprintf(stderr,"semaphore_p failed\n");return 0;}return 1;
}
static int semaphore_v(int semnum){     //释放操作,使得信号量可用,发送V信号 struct sembuf sem_b;sem_b.sem_num=semnum;sem_b.sem_op=1;sem_b.sem_flg=SEM_UNDO;if(semop(sem_id,&sem_b,1)==-1){fprintf(stderr,"semaphore_v failed\n");return 0;}return 1;
}

4.运行如图:


嘿嘿,根据有同学纠错,这道题是考虑两个进程间的并发关系。所以,我这个同步的代码不对。下面附上一篇这道题其他前辈写的代码,链接如下:
丫就是熊个猫猫



四.消息队列常用模块

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>struct my_msg_st{long int my_msg_type;char some_text[BUFSIZ];
}; int main(){int running=1;int msgid;struct my_msg_st some_data;char buffer[BUFSIZ];//创建msgid=msgget((key_t)1234,0666|IPC_CREAT);if(msgid==-1){fprintf(stderr,"megget failed with error: %d\n",errno);exit(EXIT_FAILURE);}while(running){//输入发送printf("Enter some text:");fgets(buffer,BUFSIZ,stdin);some_data.my_msg_type=1;strcpy(some_data.some_text,buffer);if(msgrcv(msgid,(void*)&some_data,BUFSIZ,msg_to_receive,0)==-1){fprintf(stderr,"msgrcv failed with error: %d\n",errno);exit(EXIT_FAILURE);}if(strncmp(some_data.some_text,"end",3)==0)break;//接收输出if(msgrcv(msgid,(void*)&some_data,BUFSIZ,msg_to_receive,0)==-1){fprintf(stderr,"msgrcv failed with error: %d\n",errno);exit(EXIT_FAILURE);}printf("You wrote: %s",some_data.some_text);}exit(EXIT_SUCCESS);
}

1

ZUCC_操作系统原理实验_Lab9进程的通信消息队列相关推荐

  1. ZUCC_操作系统原理实验_实验九 消息队列

    操作系统原理实验报告 课程名称 操作系统原理实验 实验项目名称 实验九 消息队列 实验目的 了解 Linux 系统的进程间通信机构 (IPC): 理解Linux 关于消息队列的概念: 掌握 Linux ...

  2. Linux进程之间通信 消息队列

    使用命令 ipcs -q  查看对应的消息队列 代码 文件接收者 #include <sys/types.h> #include <stdio.h> #include < ...

  3. 操作系统原理实验-进程同步

    操作系统原理实验报告 实验题目 实验二进程同步 实验二.进程同步 1.1 实验目的 现代操作系统的核心是多道程序设计.多处理器和分布式处理器,这些方案和操作系统设计技术的基础都是并发.当多个进程并发执 ...

  4. 操作系统原理实验二(三)

    继续完成操作系统原理的实验 4.5(实验目的:熟悉Window线程创建过程)在windows环境下,利用高级语言编程环境(限定为VS环境或VC环境)调用CreateThread函数实现"并发 ...

  5. 操作系统原理 实验1、2

    操作系统原理 实验1.2 1.高响应比作业调度 代码示例 #include<malloc.h> #include<stdio.h> #include<string.h&g ...

  6. 【进程】进程间通信----消息队列

    文章目录 1.消息队列 2.特性 3.实现接口 4.消息队列进程间通信 5.消息队列和命名管道的区别 5.1 相同之处 5.2 消息队列的优势 6.消息队列组织图 1.消息队列 消息队列,就是一个消息 ...

  7. 操作系统原理实验(5):内存管理

    一.实验目的 分页内存管理是内存管理的基本方法之一.本实验的目的在于全面理解分页式内存管理的基本方法以及访问页表,完成地址转换等的方法. 二.实验过程&错误 内容(一):设计不同的方式引发页错 ...

  8. 操作系统:实验一 进程调度算法

    实验一 进程调度算法 一.实验目的 用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解. 二.实验指导 设计一个有 N个进程共行的进程调度程序. 进程调度算法:分别采用先来先 ...

  9. 进程间基于消息队列的通信_Linux 进程间的通信方式

    (一)进程的概念 进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就是创建一个进程,在这个 过程中伴随着资源的分配和释放,可以认为进程是一个程序的一次执行过程. (二)进程间通信的概念 ...

最新文章

  1. 掌握深度学习,为什么要用PyTorch、TensorFlow框架?
  2. 脱机多维数据集CUB文件的生成
  3. Android动态日志系统Holmes
  4. 小白学Linux(一:开门见山)
  5. java实现蛇形输出,Java 输入一个正整数,按蛇形打印。
  6. 无限火力挤爆服务器,LOL:无限火力出炉,众多云玩家宣布回归!服务器出现爆满情况...
  7. asp.net mvc 实现上传文件带进度条
  8. 几种 vue的数据交互形式
  9. Delphi Xe Web开发之 unigui入门视频教程
  10. linux设置ipsan_linux下ipsan的配置
  11. 汽车中控语音导航服务器繁忙,交警大队智能语音导航系统解决方案
  12. 在地化和本土化的区别_本地化和翻译的本质区别在哪里?
  13. 作为程序员,每天交清晰的工作日报,不允许含糊和不详细,大家怎么看?
  14. Android--Recovery模块之恢复出厂设置
  15. FeedBack使用手册
  16. 融系统中PBOC/EMV的TLV的算法实现(含C++/C#)
  17. Unity 游戏性能优化(4)资源优化
  18. 卡西欧函数计算机广告词,学生专用卡西欧函数计算器简易空间里的排列
  19. 4.如何用代码写计算数学问题
  20. ns-3网络仿真(简易脚本解析)

热门文章

  1. 参数化三维地下管线建模关键技术研究
  2. ip iq 谐波检测matlab仿真,ip-iq谐波检测法的仿真及实验研究ip-iq谐波检测法的仿真及实验研究.pdf...
  3. Twitter数据采集案例
  4. W5500参考电路图
  5. 博客营销?软文营销?怎么按照流程走?
  6. cmd、conhost退居二线,Win 11将设置默认终端
  7. 如何在信号中添加指定信噪比的高斯白噪声,为何深度学习去噪研究采用高斯白噪声?
  8. poi-tl生成word文档,java生成word文档
  9. 在java中怎样做当鼠标选中文字单击鼠标右键出现菜单,定制鼠标右键“新建”菜单选项...
  10. 北航2020计算机学院招生,北航网络空间安全学院接收2020推免研究生复试成绩公示及相关说明...