IPC包括:消息队列、信号量、共享内存
IPC特点:
1.IPC由内核维护,存放在内核中
1.随内核持续,IPC不会自我删除,停止使用的IPC结构会一直保存在内核中,直到内核重启或者显示删除该对象。
关键字 key_t:唯一标识一个IPC,可以由ftok()函数生成
消息队列:
创建消息队列
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int qid;
key_t key;
if(argc<2){
printf("wrong parameters\n");
exit(0);
}
key = ftok(*(argv+1),'a');
if(key<0){
printf("fail to get key!\n");
exit(0);
}
qid = msgget(key,IPC_CREAT|0666);
if(qid<0){
printf("fail to create queue\n");
exit(0);
}
else{
printf("create msg queue!\n");
}
return 0;
}
key_t ftok(const char *pathname,int proj_id);
通过ftok来创建关键字,不同的路径会生成不同的消息队列的key_t值,ftok返回的key值是根据文件的物理索引创建的。
在两个路径下创建了两个消息队列的key值,注意消息队列位于内核中,只不过其key值由文件路径绑定!
ipcs -q
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
0x610718eb 65536 dxt 666 0 0
0x610718e8 98305 dxt 666 0 0
消息队列的控制
int msgctl(int maqid,int cmd,struct msqid_ds *buf);
cmd:
IPC_STAT: 在内核取此队列的msqid_ds结构, 并将它存放在buf指向的结构中.
IPC_SET: 按由buf指向结构中的值, 设置与此队列相关结构中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. (该命令只有下列两种进程可以执行: (1)有效用户ID等于msg_perm.cuid或msg_per.uid. (2)具有超级用户特权的进程. )
IPC_RMID: 从系统中删除该消息队列以及仍在该队列中的所有数据. 执行权限同上.
发送消息:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct my_msg
{
long int msg_type;
char text[BUFSIZ];
}msgbuf;
int main(int argc, char const *argv[])
{
int msgid;
int isrunnig=1;
msgid = msgget((key_t)1234,IPC_CREAT|0666);
if(msgid<0){
printf("fail to create queue\n");
exit(0);
}
else{
printf("create msg queue!\n");
}
while(isrunnig){
printf("input msg you want to send:\n");
fgets(msgbuf.text,BUFSIZ,stdin);
msgbuf.msg_type =1;
if(msgsnd(msgid,(void*)&msgbuf,BUFSIZ,0)==-1){
perror("sending failed....");
exit(0);
}
else{
printf("already send\n");
}
if(strncmp(msgbuf.text,"end",3)==0){
printf("rec end\n");
isrunnig=0;
}
}
return 0;
}
接收消息:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
struct my_msg
{
long int msg_type;
char text[BUFSIZ];
}msgbuf;
int main(int argc, char const *argv[])
{
int msgid;
long int msg_to_recv=0;
msgid = msgget((key_t)1234,IPC_CREAT|0666);
if(msgid<0){
printf("fail to create queue\n");
exit(0);
}
else{
printf("create msg queue!\n");
}
while(1){
if(msgrcv(msgid,(void*)&msgbuf,BUFSIZ,msg_to_recv,0)==-1){
perror("recv failed....");
exit(0);
}
else{
printf("the recv msg = %s\n",msgbuf.text);
}
if(strncmp(msgbuf.text,"end",3)==0){
printf("rec end\n");
break;
}
}
if(msgctl(msgid,IPC_RMID,0)==1){
perror("msgctl(IPC_RMID) fail...");
exit(1);
}
return 0;
}
BUFSIZ默认大小为8192B
只开发送进程,可以看到,发送出去的数据已经在消息队列里了:
打开接收进程:
接收进程接收到了‘ddd',并取出了消息队列中的信息。
注意! 在接收端一定要调用删除消息队列函数:
if(msgctl(msgid,IPC_RMID,0)==1){
perror("msgctl(IPC_RMID) fail...");
exit(1);
}
否自消息队列是无法自己删除的:(不调用msgctl(msgid,IPC_RMID,0)的情况)
共享内存
注意:共享内存需要信号量来同步
共享内存在解除映射时才写回文件
转自:https://blog.csdn.net/ypt523/article/details/79958188
共享 内存并未提供同步机制,也就是说,在第一个进程对共享 内 存 的 写操作结束
之前,并无自动机制可以阻止第二个进程对它进行读取 。 所以通常需要用其他的机制来同步
对共享 内存的访问 。如信号量。
例子:父子进程通过共享内存通信,以及用信号量同步
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SHM_SIZE 1024
int main(int argc, char const *argv[])
{
int ret, //临时变量
pid, //进程id
sme_id, //信号量描述符
shm_id; //共享内存描述符
key_t sme_key; //信号量键值
key_t shm_key; //共享内存键值
char *shmp; //指向共享内存首地址
struct shmid_ds dsbuf; //共享内存信息结构变量
struct sembuf lock={0,-1,SEM_UNDO}; //信号量上锁数组指针
struct sembuf unlock = {0,1,SEM_UNDO|IPC_NOWAIT};//信号量解锁数组指针
sme_key = ftok(*(argv+1),2); //
if(sme_key<0){
perror("ftok");
exit(0);
}
sme_id = semget(sme_key,1,IPC_CREAT|0666);
if(sme_id<0){
perror("semget");
exit(0);
}
shm_id = shmget(shm_key,SHM_SIZE,IPC_CREAT|0666); //获取共享内存id
if(shm_id<0){
perror("shmget");
exit(0);
}
shmp = shmat(shm_id,NULL,0); //映射共享内存
if((int)shmp==-1){
perror("shmat");
exit(0);
}
pid=fork();
if(pid<0){
perror("fork");
exit(0);
}
else if(pid==0){
ret = semctl(sme_id,0,SETVAL,1); //初始化信号量初值=1
if(ret==-1){
perror("ret");
exit(0);
}
ret =semop(sme_id,&lock,1); //p操作
if(ret==-1){
perror("semop lock");
exit(0);
}
sleep(4);
strcpy(shmp,"hello\n"); //往共享内存写数据
if(shmdt((void*)shmp)<0){ //使共享内存脱离进程地址空间
perror("shmdt");
exit(0);
}
ret =semop(sme_id,&unlock,1); //v操作
if(ret==-1){
perror("semop unlock");
exit(0);
}
}
else{
sleep(1);
ret =semop(sme_id,&lock,1);
if(ret==-1){
perror("semop lock");
exit(0);
}
if(shmctl(shm_id,IPC_STAT,&dsbuf)<0){
perror("shmctl");
exit(0);
}
else{
printf("get share mem info\n");
printf("creater pid =%d\n",dsbuf.shm_cpid);
printf("recv msg=%s\n",(char*)shmp);
}
if(shmdt((void*)shmp)<0){
perror("shmdt");
exit(0);
}
ret =semop(sme_id,&unlock,1);
if(ret==-1){
perror("semop unlock");
exit(0);
}
//记得删除信号量和共享内存
if(shmctl(shm_id,IPC_RMID,NULL)<0){
perror("shmctl");
exit(0);
}
ret =semctl(sme_id,0,IPC_RMID,NULL);
if(ret==-1){
perror("semctl");
exit(0);
}
}
return 0;
}
输出:
get share mem info
creater pid =17494
recv msg=hello
注意:与消息队列一样,父进程退出时需要删除共享内存和信号量!
否则,会看到进程退出时,共享内存和信号量仍未释放
dxt@DXT:~/Desktop/SHI_XI/msgque$ ipcs -m
------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 连接数 状态0x2f2f2f2f 29425693 dxt 666 1024 0
dxt@DXT:~/Desktop/SHI_XI/msgque$ ipcs -s
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
0x020718f1 0 dxt 666 1
就以两个不相关的进程来说明进程间 如何通过共享 内存来进行通信 。 其中 一个文
件 consumer.cpp 创建共享内存,并读取其中的信息 ,另 一个文件 producer.cpp 向共享 内存中
写人数据 。结构 shared_use_st 中的 written 作为一个可读或可写的标志,非 0 表示可读, 0
表示可写, text 则是 内存中的文件 。
producer.cpp
#include<sys/shm.h>
#define TEXT_SIZE 2048
struct shared_use_st{
int written;
char text[TEXT_SIZE];
};
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>
#define CHECK(x,...) if(x==-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}
#define CHECK_MEM(x,...) if(x==(void*)-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}
int main(){
int shmid;
shmid = shmget((key_t)1234,sizeof(shared_use_st),0666|IPC_CREAT);
CHECK(shmid,"falied to get share memory")
void* shared_memory = (void*)0;
shared_memory = shmat(shmid,(void*)0,0);
CHECK_MEM(shared_memory,"shmat fail")
struct shared_use_st *share_stuff;
share_stuff = (struct shared_use_st*)shared_memory;
int running=1;
char buffer[BUFSIZ];
while(running){
while(share_stuff->written==1){
sleep(1);
printf("waiting for client ...\n");
}
printf("Enter some text\n");
fgets(buffer,BUFSIZ,stdin);
strncpy(share_stuff->text , buffer,TEXT_SIZE) ;
share_stuff->written = 1;
if (strncmp(buffer,"end",3) == 0) {
running = 0;
}
}
CHECK(shmdt(shared_memory),"shmdt failed\n")
exit(EXIT_SUCCESS);
}
consumer.cpp
#include<sys/shm.h>
#define TEXT_SIZE 2048
struct shared_use_st{
int written;
char text[TEXT_SIZE];
};
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>
#include<iostream>
#define CHECK(x,...) if(x==-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}
#define CHECK_MEM(x,...) if(x==(void*)-1){fprintf(stderr,__VA_ARGS__);exit(EXIT_FAILURE);}
int main(){
int shmid;
shmid = shmget((key_t)1234,sizeof(shared_use_st),0666|IPC_CREAT);
CHECK(shmid,"shmid failed")
void* share_memory = (void*)0;
share_memory = shmat(shmid,(void*)0,0);
CHECK_MEM(share_memory,"shmat failed");
printf("Memery attached at %X \n",(long)share_memory);
struct shared_use_st *shared_stuff;
shared_stuff=(struct shared_use_st *)share_memory;
shared_stuff->written = 0;
int running = 1;
while(running){
printf("shared_stuff->written:%d\n",shared_stuff->written);
if(shared_stuff->written){
printf("you write %s",shared_stuff->text);
sleep(rand()%4);
shared_stuff->written=0;
if(strncmp(shared_stuff->text,"end",3)==0)
running = 0;
}
}
CHECK(shmdt(share_memory),"shmdt failed")
CHECK(shmctl(shmid,IPC_RMID,0),"shmctl(shmid,IPC_RMID,0) failed")
exit(EXIT_SUCCESS);
}
共享内存为 share_stuff = (struct shared_use_st*)shared_memory;