進程間通信(四)—共享內存


我會用幾篇博客總結一下在Linux中進程之間通信的幾種方法,我會把這個開頭的摘要部分在這個系列的每篇博客中都打出來

進程之間通信的方式

  • 管道
  • 消息隊列
  • 信號
  • 信號量
  • 共享存儲區
  • 套接字(socket)

進程間通信(五)—信號傳送門:http://www.cnblogs.com/lenomirei/p/5656449.html

進程間通信(三)—信號量傳送門:http://www.cnblogs.com/lenomirei/p/5649792.html

進程間通信(二)—消息隊列傳送門:http://www.cnblogs.com/lenomirei/p/5642575.html

進程間通信(一)—管道傳送門:http://www.cnblogs.com/lenomirei/p/5636339.html

這篇主要記錄的是共享存儲區的相關操作,說是共享存儲區,其實就是共享內存,進程擁有的能互相通信存儲區也就有內存了吧

為什么用共享存儲區進行通信?因為快!管道是文件,操作慢,消息隊列創建操作都有消耗所以慢,共享內存是要創建好兩個進程都可以直接對這塊內存進行操作,互相都是可見的。

為什么用共享存儲區編寫程序?因為接口簡單!操作絕對比消息隊列簡單好多。

  • 創建共享存儲區

雖然感覺很簡單的事情,但是還是要創建開辟一下,不然每個進程都用自己的地址空間映射到不同的物理地址,哪怕虛擬地址是一樣的,也是各自獨立的,互相不可見,聲明了這個共享存儲區之后,才可以往這個公共的區域映射(這樣才有用不是么)。

  • 函數原型:int shmget(key_t key, size_t size, int shmflg);
  • 頭文件:#include <sys/ipc.h> #include <sys/shm.h>
  • 參數解析
    • key參數通過ftok函數的返回值取得,或者傳入IPC_PRIVATE由操作系統自動分配
    • size表示你要開辟多大的共享存儲空間,PS:分配空間最終會變成分配物理空間,是通過分配整頁的方式實現的,Linux系統下一頁大小是4KB=4096B,小於4096B則分配一頁,size傳入4097則分配兩頁
    • shmflg有IPC_CREAT 和 IPC_EXCL

調用這個函數就可以開辟一個共享存儲區了,可以通過ipcs -m查看當前共享存儲區狀態

第一個鍵值就是傳入的key,shmid標識唯一共享內存段,擁有者權限字節就不多說了額,這個nattch是指當前有多少個進程連接到該共享存儲區

nattch:只創建共享存儲區是不夠的,你需要把它和進程鏈接,才能讓進程的地址空間中的一段地址映射到共享內存段上。

  • 共享存儲區的連接

這就講一下用什么函數鏈接共享存儲區,需要注意的是,兩個進程都需要鏈接才可以,創建共享存儲區的進程不會自動連接,也需要調用鏈接函數

  • 函數原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
  • 頭文件:#include <sys/types.h> #include <sys.shm.h>
  • 參數解析
    • shmid表示共享存儲區的標識
    • 第二個參數表示共享存儲區的開始地址,如果不是對內存十分了解建議交給操作系統去做,設置為0
    • shmflg可以設置當前進程的讀寫權限,SEM_RDONLY之類的,默認0為讀寫均可,測試程序我給了0

每有一個進程調用這個函數,就會使nattch增加1,返回值因為是個空類型的指針常常需要強制轉換

  • 共享存儲區的鏈接的斷開

鏈接使用完之后就斷開是個好習慣,而且對銷毀共享存儲空間也好

  • 函數原型:int shmdt(const void *shmaddr);
  • 頭文件:#include <sys/types.h> #include <sys.shm.h>
  • 參數解析刪除共享存儲區
    • 就是要刪除的共享存儲區的起始地址,因為是空類型的指針,沒必要轉換,直接給來都能刪除

 

 

  • 刪除共享存儲區

最后還是要用到shmctl函數來刪除共享存儲區

  • 函數原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • 頭文件:#include <sys/ipc.h> #include <sys/shm.h>
  • 參數解析
    • shmid表示共享存儲區的標識
    • cmd給出IPC_RMID表示刪除
    • 因為第二個參數設置為IPC_RMID表示刪除,第三個參數沒用了,第三個參數直接給NULL(0)

 

事已至此,基本操作就說完了,廢話少說,show me the code

我的程序分為comm.h(公共頭文件)  comm.c(封裝基本函數) server.c(簡易服務器端) 一共3個文件

功能主要實現了簡單的字符串共享?父進程寫入,子進程打印,就這么簡單

結果圖並看不出什么鬼

comm.h

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <string.h>
 4 #include <sys/ipc.h>
 5 #include <unistd.h>
 6 #include <sys/shm.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 
10 
11 #define _PATH_NAME_ "/tmp"
12 #define _PROJ_ID_ 0x6666
13 
14 
15 
16 static int comm_create_ssm(int flags,size_t size); 17 int create_shm(size_t size); 18 int get_shm(); 19 char *shm_at(int shm_id); 20 void destory_shm(int shm_id); 21 int shm_dt(char *addr);

 

comm.c

 1 #include "comm.h"
 2 
 3 
 4 static int comm_create_shm(int flags,size_t size)  5 {  6   key_t _key=ftok(_PATH_NAME_,_PROJ_ID_);  7   if(_key<0)  8  {  9     printf("%d:%s",errno,strerror(errno)); 10  } 11   int shm_id; 12   if((shm_id=shmget(_key,size,flags))<0) 13  { 14     printf("shmget error,%d:%s",errno,strerror(errno)); 15  } 16   return shm_id; 17 } 18 
19 
20 int create_shm(size_t size) 21 { 22   int flags=IPC_CREAT |IPC_EXCL; 23   return comm_create_shm(flags,size); 24 } 25 
26 int get_shm() 27 { 28   int flags=IPC_CREAT; 29   return comm_create_shm(flags,0); 30 } 31 
32 char *shm_at(int shm_id) 33 { 34   return (char *)shmat(shm_id,NULL,0); 35 } 36 int shm_dt(char *addr) 37 { 38   return shmdt(addr); 39 } 40 
41 void destory_shm(int shm_id) 42 { 43   shmctl(shm_id,IPC_RMID,0); 44 }

 

server.c

 1 #include "comm.h"
 2 
 3 
 4 
 5 int main()  6 {  7   int pid=fork();  8   if(pid>0)  9  { 10     //father
11     int shm_id=create_shm(4096); 12     char *buf=shm_at(shm_id); 13     int i=0; 14     while(i<4096) 15  { 16       sleep(1); 17       buf[i]='A'; 18       i++; 19       buf[i]='\0'; 20  } 21  } 22   else
23  { 24     //child
25     int shm_id=get_shm(); 26     char *buf=shm_at(shm_id); 27     while(1) 28  { 29       sleep(1); 30       printf("%s\n",buf); 31  } 32  } 33   return 0; 34 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM