C++ 进阶 day12 多进程编程
system V提供的进程间通信
-
对于内核提供的三种通信方式,对于管道而言,只能实现单向的数据通信,对于信号通信而言,只能完成多进程之间消息的通知,不能起到数据传输的效果。为了解决上述问题,引入的系统V进程间通信
-
system V提供的进程间通信方式分别是:消息队列、共享内存、信号量(信号灯集)
-
有关system V进程间通信对象相关的指令
-
ipcs :可以查看所有消息队列(消息队列,内存共享,信号量)
-
ipcs -q:可以查看消息队列
-
ipcs -m:可以查看共享内存的消息
-
ipcs -s:可以查看信号量的信息
-
ipcrm -q/m/s ID:可以删除指定ID的IPC对象
-
上述的三种通信方式,也是借助内核空间完成的相关通信,原理是在内核空间创建出相关的对象容器,在进行进程间通信时,可以将信息放入对象中,另一个进程就可以从该容器中取数据了。
-
与内核提供的管道、信号通信不同:system V的ipc对象实现了数据传递的容器与程序相分离,也就是说,即使程序以己经结束,但是放入到容器中的数据依然存在,除非将容器手动删除
消息队列
实现原理

消息队列实现的API
创建key值
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);//ftok("/",'k');
功能:通过给定的文件以及给定的一个随机值,创建出一个4字节整数的key值,用于system V IPC对象的创建
- 参数1:一个文件路径,要求是已经存在的文件路径,提供了key值3字节的内容,其中文件的设备号占1字节,文件的inode号占2字节
- 参数2:一个随机整数,取后8位(1字节)跟前面的文件共同组成key值,必须是非0的数字
- 返回值:成功返回key值,失败返回-1并置位错误码
通过key值,创建消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
好多头文件(
int msgget(key_t key, int msgflg);
- 功能:通过给定的key值,创建出一个消息队列的对象,并返回消息队列的句柄ID,后期可以通过该ID操作整个消息队列
- 参数1:key值,该值可以是IPC_PRIVATE,也可以是ftok创建出来的,前者只用于亲缘进程间的通信
- 参数2:创建标识
- IPC_CREAT:创建并打开一个消息队列,如果消息队列已经存在,则直接打开
- IPC_EXCL:确保本次创建处理的是一个新的消息队列,如果消息队列已经存在,则报错,错误码位EEXIST
- 0664:该消息队列的操作权限
- 返回值:成功返回消息队列的ID号,失败返回-1并置位错误码
向消息队列中存放数据
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- 功能:向消息队列中存放一个指定格式的消息
- 参数1:打开的消息队列的id号
- 参数2:要发送的消息的起始地址,消息一般定义为一个结构体类型,由用户手动定义
struct msgbuf{
long mtype;//消息类型
char mtext[1];//详细内容
。。。
}
- 参数3:消息正文的大小(宏定义mtext)
- 参数4:是否阻塞的标识
- 0:标识阻塞形式向消息队列中存放消息,如果消息队列满了,就在该函数处阻塞
- IPC_NOWAIT:标识非阻塞的形式向消息队列中存放消息,如果消息队列满了,直接返回
- 返回值:成功返回0,失败返回-1并置位错误码
从消息队列中取消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int
msgflg);
- 功能:
- 参数1:
- 参数2:
struct msgbuf {
long mtype; /* message type, must be > 0 */ 消息的类型
char mtext[1]; /* message data */ 消息正文
。。。
};
- 参数3:消息正文的大小
- 参数4:要接收的消息类型
- 0:表示每次都取消息队列中的第一个消息,无论类型
- 大于0:读取队列中第一个类型为msgtyp的消息
- 小于0:读取队列中的一个消息,消息为绝对值小于msgtyp的第一个消息
eg: 10-->8-->3-->6-->5-->20-->2
-5: 会从队列中绝对值小于5的类型的消息中选取第一个消息,就是3
- 参数5:是否阻塞的标识
- 0:标识阻塞形式向消息队列中读取消息,如果消息队列空了,就在该函数处阻塞
- IPC_NOWAIT:标识非阻塞的形式向消息队列中读取消息,如果消息队列空了,直接返回
- 返回值:成功返回实际读取的正文大小,失败返回-1并置位错误码
销毁消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 功能:对给定的消息队列执行相关的操作,该操作由cmd参数而定
- 参数1:消息队列的ID号
- 参数2:要执行的操作
- IPC_RMID:删除一个消息队列,当cmd为该值时,第三个参数可以省略填NULL即可
- IPC_STAT:表示获取当前消息队列的属性,此时第三个参数就是存放获取的消息队列属性的容器起始地址
- IPC_SET:设置当前消息队列的属性,此时第三个参数就是要设置消息队列的属性数据的起始地址
实践
发送端
#include <myhead.h>
//消息类型的定义
struct msgBuf{
long mtype;
char mtext[1024];
};
#define MSGSZ (sizeof(struct msgBuf)-sizeof(long)) //正文的大小
int main(){
//1.创建key值,用于创建出一个消息队列
key_t key=ftok("/",'k');
//参数1:已经存在的路径
//参数2:是一个随机值
printf("key = %#x\n",key);
//2.通过key值创建出消息队列,并返回该消息队列的id
int msqid=-1;
if((msqid=msgget(key,IPC_CREAT|0664))==-1){
perror("msgget error");
return -1;
}
printf("msggid = %d\n",msqid);//输出id号
//3.像消息队列中存放消息
//组建一个消息
struct msgBuf buf;
while(1){
printf("请输入消息的类型:");
scanf("%ld",&buf.mtype);
getchar();//吸收回车fgets()
printf("请输入消息正文:");
fgets(buf.mtext,MSGSZ,stdin);//从终端中输入数据
//1.指针地址
//2.大小
//3.特殊标识符标准输入0,1,2 没有引入其他文件
buf.mtext[strlen(buf.mtext)-1]='\0';
//4.将上述组装的消息放入消息队列中,以阻塞的方式将其放入消息队列
msgsnd(msqid,&buf,MSGSZ,0);
//1.id号
//2.地址
//3.大小
//4.处理形式,队列为空时堵塞
printf("消息存入成功\n");
//判断推出条件
if(strcmp(buf.mtext,"quit")==0){
break;
}
}
return 0;
}
接收端
#include <myhead.h>
//消息类型的定义
struct msgBuf{
long mtype; //消息类型
char mtext[1024]; //消息正文
};
#define MSGSZ (sizeof(struct msgBuf)-sizeof(long))
int main(){
//1.创建key值,用于创建出一个消息队列
key_t key = ftok("/",'k');
//参数1:已经存在的路径
//参数2:是个随机数
if(key==-1){
perror("ftok error");
return -1;
}
printf("key = %#x\n",key);
//2.通过key值创建出一个消息队列,并返回该消息队列的id
int msqid=-1;
if((msqid=msgget(key,IPC_CREAT|0664))==-1){
perror("msgget error");
return -1;
}
printf("msgqid = %d\n",msqid);
//3.从消息队列中取出消息
//组建一个消息
struct msgBuf buf;
while(1){
//清空容器
bzero(&buf,sizeof(buf));
//读取信息
msgrcv(msqid, &buf, MSGSZ, 1, 0);
//参数4:表示读取的消息类型
//参数5:是否堵塞
printf("读取到的消息类型为:%s\n",buf.mtext);
if(strcmp(buf.mtext,"quit")==0){
break;
}
}
//4.删除消息对列
if(msgctl(msqid,IPC_RMID,NULL)==-1){
perror("msgctl error");
return -1;
}
return 0;
}
分屏观察:


浙公网安备 33010602011771号