Linux c 基于内存的进程通信—共享内存、共享队列(消息队列)
基于內(nèi)存的進(jìn)程通信:
1.??????內(nèi)核共享內(nèi)存
編程模型:
?? ?1.1.創(chuàng)建共享內(nèi)存,得到一個(gè)ID? shmget
1.2.把ID影射成虛擬地址(掛載)? shmat
?????? 1.3.使用虛擬地址訪問(wèn)內(nèi)核共享內(nèi)存使用任何內(nèi)存函數(shù)與運(yùn)算符號(hào)??????????????????????? 1.4.卸載虛擬地址 shmdt
?????? 1.5.刪除共享內(nèi)存 shctl(修改/獲取共享內(nèi)存的屬性)
?
案例:
A.創(chuàng)建共享內(nèi)存,并且修改內(nèi)存數(shù)據(jù)
1.??????創(chuàng)建共享內(nèi)存
??????????????????????????????#include<sys/shm.h>
??????????????????????????????intshmget(key_t key,//為什么需要key
????????????????????????????????????????????????????????????????????? ?int size,//共享內(nèi)存大小
????????????????????????????????????????????????????????????????????? ?int flags//共享內(nèi)存的屬性與權(quán)限
???????????????????????????????????????????????? )
????????????????????????????????????????? 為什么要key_t:
??????????????????????????????????????????????????????? 約定創(chuàng)建與訪問(wèn)的是同一個(gè)共享內(nèi)存。Key為兩個(gè)進(jìn)程之間訪問(wèn)同一塊共享內(nèi)存的約定
注:key需要唯一性,因?yàn)槲覀儾荒鼙WC我們自己定義的key的唯一性,所以為了保證kay的唯一性,我們需要用某個(gè)文件對(duì)應(yīng)的整數(shù)來(lái)充當(dāng)kay值,可以用ftok函數(shù)來(lái)將一個(gè)文件轉(zhuǎn)化為一個(gè)kay值。(一般我們用兩個(gè)進(jìn)程的共同的工程目錄文件來(lái)確定kay值)
?
???????????????????????? ftok函數(shù):
??????????????????????????????????#include<sys/ipc.h>
?????????????????????????????????? key_t ??ftok( const char * pathname,int? proj_id);
???????????????????????? ??????????參數(shù)二:一個(gè)控制因子。建議在0—255之間
????????????????????????????????????????? 第三個(gè)參數(shù):
?????????????????????????????????????????????????????????????? 方式|權(quán)限
?????????????????????????????????????????????????????????????? 方式:創(chuàng)建 IPC_CREAT? IPC_EXCL(如果內(nèi)存已經(jīng)創(chuàng)建,直接錯(cuò)誤返回)
?????????????????????????????????????????????????????????????? 打開(kāi):0
??????????????????????????????????????????????????????? 常見(jiàn)的兩種方式:
????????????????????????????????????????????????????????????????????? 創(chuàng)建:IPC_CREAT|IPC_EXCL | 0666;
????????????????????????????????????????????????????????????????????? 打開(kāi):0
????????????????????????????????????????????????????????????????????????????
?????????????????????????????????? 返回:
???????????????????????????????????????????????? 成功返回共享內(nèi)存ID
???????????????????????????????????????????????? 失敗返回-1?????????????????
?????? ???????????????????? 失敗返回-1?????????????????
???????????????????? B.根據(jù)ID得到共享內(nèi)存,并且訪問(wèn)內(nèi)存數(shù)據(jù)。
?
?????????????????????????????????? 掛載共享內(nèi)存
void* shmat(int id,
???????????????????????????????????????????????? void*startaddr,//0:系統(tǒng)指定首地址
???????????????????????????????????????????????? intflags)//掛載方式,建議0默認(rèn)讀寫(xiě),可以使用IPC_RDONLY
???????????????????????????? 返回值:合法地址成功,-1失敗
???????????????????? C.刪除
?????????????????????????????????? intshmctl(int id,//被操作的共享內(nèi)存ID
???????????????????????????????????????????????? inthow,//操作方式:一共三種操作
???????????????????????????????????????????????? structshmid_ds*ds)//共享內(nèi)存屬性
?????????????????????????????????? how:
???????????????????????????????????????????????? IPC_STAT???
???????????????????????????????????????????????? IPC_SET???? //修改屬性
???????????????????????????????????????????????? IPC_RMID?? //刪除?? 參數(shù)三無(wú)用
?
?
案例代碼:
ShmA.c
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/shm.h>
#include<sys/ipc.h>
?
void???main()
{
??????key_t?? key;
??????int???? shmid;
??????int * p;
??????//1.創(chuàng)建共享內(nèi)存
??????key=ftok( “.” , 255 );?? //用當(dāng)前路徑的目錄來(lái)確定kay值
??????if(key == -1)? printf(“ftok error%m\n”) ,? exit( - 1 );
??????shmid=shmget( key , 4 , IPC_CREAT|IPC_EXCL | 0666 );
??????if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );
??????//2.掛載共享內(nèi)存
??????p=shmat( shmid , 0 , 0);
??????if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );
??????//3.訪問(wèn)共享內(nèi)存
??????*p=999;
??????//4.卸載共享內(nèi)存
??????shmdt(shmid);
??????//刪除共享內(nèi)存
??????shctl( shmid , IPC_RMID , 0);
}
不創(chuàng)建共享內(nèi)存,只訪問(wèn)已有的
shmB.c
?
ShmA.c
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<sys/shm.h>
#include<sys/ipc.h>
?
void???main()
{
??????key_t?? key;
??????int???? shmid;
??????int * p;
??????//1.得到共享內(nèi)存
??????key=ftok( “.” , 255 );?? //用當(dāng)前路徑的目錄來(lái)確定kay值
??????if(key == -1)? printf(“ftok error%m\n”) ,? exit( - 1 );
??????shmid=shmget( key , 4 ,0 );
??????if(shmid == -1) printf(“shmget error %m\n”) , exit( -1 );
??????//2.掛載共享內(nèi)存
???? ??p=shmat( shmid , 0 , 0);
??????if(p==(int *) - 1) printf(“at error %m\n”) , exit( -1 );
??????//3.訪問(wèn)共享內(nèi)存
??????printf(“%d\n”,*p);
??????//4.卸載共享內(nèi)存
??????shmdt(shmid);
????
}
?
?
2.??????內(nèi)核共享隊(duì)列(有序)
??? ????????編程模型:
????????????????????????????????????????? 2.1.創(chuàng)建共享隊(duì)列/得到隊(duì)列msgget
????????????????????????????????????????? 2.2.使用隊(duì)列(發(fā)送消息msgsnd/接收消息msgrcv)
????????????????????????????????????????? 2.3.刪除隊(duì)列msgctl
?
案例:
???????????????????? 創(chuàng)建共享隊(duì)列
???????????#include<sys/msg.h>
?????????????????????????????????? intmsgget(key_t,int); 除了不用指定大小,和shmget函數(shù)的參數(shù)一樣?????????????????????????????
???????????????????? 發(fā)送消息
?????????????????????????????????? intmsgsnd(
???????????????????????????????????????????????? intid,//消息隊(duì)列ID
???????????????????????????????????????????????? constvoid *msg,//要發(fā)送消息
???????????????????????????????????????????????? size_tlen,//消息的長(zhǎng)度
???????????????????? ??????????????????????????? int flags//發(fā)送消息的方式,建議為0
????????????????????????????????????????? );
?????????????????????????????????? 返回:
???????????????????????????????????????????????? -1:失敗
???????????????????????????????????????????????? ?0:成功??
?????????????????????????????????? 第二個(gè)參數(shù)的消息有固定的格式
??????????????????????????????????????????????????????? 4字節(jié):表示消息的類型
??????????????????????????????????????????????????????? 若干字節(jié):消息內(nèi)容。
??????????????????? ?消息格式:(該結(jié)構(gòu)體需要我們自己定義)
????????????????????????????? struct? msgbuf{
?????????????????????????????????? long?? mtype;?//消息類型
?????????????????????????????????? char?? mtext[1]; //消息內(nèi)容
????????????????????????????? }
?????????????????????????????????? 第三個(gè)參數(shù):
??????????????????????????????????????????????????????? 消息的大小,不包含類型的4個(gè)字節(jié)
????????????? 接收消息:
?????????????????????? size_t?? msgrcv(int id ,
void * msgp ,
size_t msgsz, ,
long msgtype , //那種類型的消息
int? msgflg);
????????????????????? 返回:
?????????????????????????? -1:失敗
?????????????????????????? 大小:成功
?????????????? 刪除隊(duì)列:msgctl 參數(shù)和shctl一樣
?
案例代碼:
?
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
?
struct??msgbuf
{
?????long? type;
?????char? data[32];
}
?
void?main()
{
????key_t? key;
????int msgid;
????//1創(chuàng)建消息隊(duì)列
???? key= ftok(“ . ” , 254);
????if(key == -1) printf(“ftok error:%m\n”) , exit(-1);
????msgid= msgget(key,IPC_CREAT | IPC_EXCL|0666);
???? if(msgid==-1) printf(“get error : %m\n”), exit(-1);
????//2構(gòu)造消息
???? struct? msgbuf msg;
????//3發(fā)送消息
???? for(i=1;i<=10;i++)
????{
??????????msg.type=1;??????? //消息類型自己定義一個(gè)long類型
??????????sprintf(msg.data? , “Message:%d”,i);
??????????msgsnd(msgid ,&msg , strlen(msg.data) , 0);
????}
????//4刪除隊(duì)列
???? //msgctl(msgid, IPC_RMID,0);
}
?
?
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
?
struct??msgbuf
{
?????long? type;
?????char? data[32];
}
?
void?main()
{
????key_t? key;
????int msgid;
????//1得到消息隊(duì)列
????key = ftok(“ . ” , 254);
????if(key == -1) printf(“ftok error:%m\n”) , exit(-1);
????msgid= msgget(key,0);
????if(msgid== -1) printf(“get error : %m\n”), exit(-1);
????//2構(gòu)造消息
???? struct? msgbuf msg;
????//3接收消息
???? while(1)
????{
?????????bzero(&msg,sizeof(msg));
?????????msgrcv(msgid , & msg sizeof(msg.data) , 1 , 0);
?????????printf(“%s\n”,msg.data);
????}
}
?
說(shuō)明:如果消息隊(duì)列中沒(méi)有消息了讀取消息的程序會(huì)阻塞等待
當(dāng)程序發(fā)送消息到隊(duì)列中,一個(gè)程序讀取了所以消息,隊(duì)列中就沒(méi)有消息,就無(wú)法再讀取了,只能等待在發(fā)送消息后在讀取消息。
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/bbsno1/p/3260627.html
總結(jié)
以上是生活随笔為你收集整理的Linux c 基于内存的进程通信—共享内存、共享队列(消息队列)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 深度探索C++对象模型读书笔记-第六章执
- 下一篇: 另类的 高版本数据库 转换到 低版本数