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