加入星計劃,您可以享受以下權益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 8.5  共享內(nèi)存
  • 相關推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

進程間通信之: 共享內(nèi)存

2013/09/13
閱讀需 20 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

?

8.5??共享內(nèi)存

8.5.1??共享內(nèi)存概述

可以說,共享內(nèi)存是一種最為高效的進程間通信方式。因為進程可以直接讀寫內(nèi)存,不需要任何數(shù)據(jù)的復制。為了在多個進程間交換信息,內(nèi)核專門留出了一塊內(nèi)存區(qū)。這段內(nèi)存區(qū)可以由需要訪問的進程將其映射到自己的私有地址空間。因此,進程就可以直接讀寫這一內(nèi)存區(qū)而不需要進行數(shù)據(jù)的復制,從而大大提高了效率。當然,由于多個進程共享一段內(nèi)存,因此也需要依靠某種同步機制,如互斥鎖和信號量等(請參考本章的共享內(nèi)存實驗)。其原理示意圖如圖8.8所示。

圖8.8??共享內(nèi)存原理示意圖

8.5.2??共享內(nèi)存的應用

1.函數(shù)說明

共享內(nèi)存的實現(xiàn)分為兩個步驟,第一步是創(chuàng)建共享內(nèi)存,這里用到的函數(shù)是shmget(),也就是從內(nèi)存中獲得一段共享內(nèi)存區(qū)域,第二步映射共享內(nèi)存,也就是把這段創(chuàng)建的共享內(nèi)存映射到具體的進程空間中,這里使用的函數(shù)是shmat()。到這里,就可以使用這段共享內(nèi)存了,也就是可以使用不帶緩沖的I/O讀寫命令對其進行操作。除此之外,當然還有撤銷映射的操作,其函數(shù)為shmdt()。這里就主要介紹這3個函數(shù)。

2.函數(shù)格式

表8.20列舉了shmget()函數(shù)的語法要點。

表8.20 shmget()函數(shù)語法要點

所需頭文件

#include?<sys/types.h>
#include?<sys/ipc.h>
#include?<sys/shm.h>

函數(shù)原型

int?shmget(key_t?key,?int?size,?int?shmflg)

函數(shù)傳入值

key:共享內(nèi)存的鍵值,多個進程可以通過它訪問同一個共享內(nèi)存,其中有個特殊值IPC_PRIVATE。它用于創(chuàng)建當前進程的私有共享內(nèi)存

size:共享內(nèi)存區(qū)大小

shmflg:同open()函數(shù)的權限位,也可以用八進制表示法

函數(shù)返回值

成功:共享內(nèi)存段標識符

出錯:-1

表8.21列舉了shmat()函數(shù)的語法要點。

表8.21 shmat()函數(shù)語法要點

所需頭文件

#include?<sys/types.h>
#include?<sys/ipc.h>
#include?<sys/shm.h>

函數(shù)原型

char?*shmat(int?shmid,?const?void?*shmaddr,?int?shmflg)

函數(shù)傳入值

shmid:要映射的共享內(nèi)存區(qū)標識符

shmaddr:將共享內(nèi)存映射到指定地址(若為0則表示系統(tǒng)自動分配地址并把該段共享內(nèi)存映射到調(diào)用進程的地址空間)

shmflg?

SHM_RDONLY:共享內(nèi)存只讀

默認0:共享內(nèi)存可讀寫

函數(shù)返回值

成功:被映射的段地址

出錯:-1

表8.22列舉了shmdt()函數(shù)的語法要點。

表8.22 shmdt()函數(shù)語法要點

所需頭文件

#include?<sys/types.h>
#include?<sys/ipc.h>
#include?<sys/shm.h>

函數(shù)原型

int?shmdt(const?void?*shmaddr)

函數(shù)傳入值

shmaddr:被映射的共享內(nèi)存段地址

函數(shù)返回值

成功:0

出錯:-1

?

3.使用實例

該實例說明如何使用基本的共享內(nèi)存函數(shù)。首先是創(chuàng)建一個共享內(nèi)存區(qū)(采用的共享內(nèi)存的鍵值為IPC_PRIVATE,是因為本實例中創(chuàng)建的共享內(nèi)存是父子進程之間的共用部分),之后創(chuàng)建子進程,在父子兩個進程中將共享內(nèi)存分別映射到各自的進程地址空間之中。

父進程先等待用戶輸入,然后將用戶輸入的字符串寫入到共享內(nèi)存,之后往共享內(nèi)存的頭部寫入“WROTE”字符串表示父進程已成功寫入數(shù)據(jù)。子進程一直等到共享內(nèi)存的頭部字符串為“WROTE”,然后將共享內(nèi)存的有效數(shù)據(jù)(在父進程中用戶輸入的字符串)在屏幕上打印。父子兩個進程在完成以上工作之后,分別解除與共享內(nèi)存的映射關系。

最后在子進程中刪除共享內(nèi)存。因為共享內(nèi)存自身并不提供同步機制,所以應該額外實現(xiàn)不同進程之間的同步(例如:信號量)。為了簡單起見,在本實例中用標志字符串來實現(xiàn)非常簡單的父子進程之間的同步。

這里要介紹的一個命令是ipcs,這是用于報告進程間通信機制狀態(tài)的命令。它可以查看共享內(nèi)存、消息隊列等各種進程間通信機制的情況,這里使用了system()函數(shù)用于調(diào)用shell命令“ipcs”。程序源代碼如下所示:

/*?shmem.c?*/

#include?<sys/types.h>

#include?<sys/ipc.h>

#include?<sys/shm.h>

#include?<stdio.h>

#include?<stdlib.h>

#include?<string.h>

#define?BUFFER_SIZE?2048

int?main()

{

????pid_t?pid;

????int?shmid;

????char?*shm_addr;

????char?flag[]?=?"WROTE";

????char?*buff;

????

????/*?創(chuàng)建共享內(nèi)存?*/

????if?((shmid?=?shmget(IPC_PRIVATE,?BUFFER_SIZE,?0666))?<?0)

????{

????????perror("shmget");

????????exit(1);

????}

????else

????{

????????printf("Create?shared-memory:?%dn",shmid);

????}

????

????/*?顯示共享內(nèi)存情況?*/

????system("ipcs?-m");

????

????pid?=?fork();

????if?(pid?==?-1)

????{

????????perror("fork");

????????exit(1);

????}

????else?if?(pid?==?0)?/*?子進程處理?*/

????{

????????/*映射共享內(nèi)存*/

????????if?((shm_addr?=?shmat(shmid,?0,?0))?==?(void*)-1)

????????{

????????????perror("Child:?shmat");

????????????exit(1);

????????}

????????else

????????{

????????????printf("Child:?Attach?shared-memory:?%pn",?shm_addr);

????????}

????????system("ipcs?-m");

????????

????????/*?通過檢查在共享內(nèi)存的頭部是否標志字符串"WROTE"來確認

父進程已經(jīng)向共享內(nèi)存寫入有效數(shù)據(jù)?*/

????????while?(strncmp(shm_addr,?flag,?strlen(flag)))

????????{

????????????printf("Child:?Wait?for?enable?data...n");

????????????sleep(5);

????????}

????????

????????/*?獲取共享內(nèi)存的有效數(shù)據(jù)并顯示?*/

????????strcpy(buff,?shm_addr?+?strlen(flag));

????????printf("Child:?Shared-memory?:%sn",?buff);

????????

????????/*?解除共享內(nèi)存映射?*/

????????if?((shmdt(shm_addr))?<?0)

????????{

????????????perror("shmdt");

????????????exit(1);

????????}

????????else

????????{

????????????printf("Child:?Deattach?shared-memoryn");

????????}

????????system("ipcs?-m");

??????????

????????/*?刪除共享內(nèi)存?*/

????????if?(shmctl(shmid,?IPC_RMID,?NULL)?==?-1)

????????{

????????????perror("Child:?shmctl(IPC_RMID)n");

????????????exit(1);

????????}

????????else

????????{

????????????printf("Delete?shared-memoryn");

????????}

????????

????????system("ipcs?-m");

????}

????else?/*?父進程處理?*/

????{

????????/*映射共享內(nèi)存*/

????????if?((shm_addr?=?shmat(shmid,?0,?0))?==?(void*)-1)

????????{

????????????perror("Parent:?shmat");

????????????exit(1);

????????}

????????else

????????{

????????????printf("Parent:?Attach?shared-memory:?%pn",?shm_addr);

????????}

????????

????????sleep(1);

????????printf("nInput?some?string:n");

????????fgets(buff,?BUFFER_SIZE,?stdin);

????????strncpy(shm_addr?+?strlen(flag),?buff,?strlen(buff));

????????strncpy(shm_addr,?flag,?strlen(flag));

????????

????????/*?解除共享內(nèi)存映射?*/

????????if?((shmdt(shm_addr))?<?0)

????????{

????????????perror("Parent:?shmdt");

????????????exit(1);

????????}

????????else

????????{

????????????printf("Parent:?Deattach?shared-memoryn");

????????}

????????system("ipcs?-m");

????????

????????waitpid(pid,?NULL,?0);????????

????????printf("Finishedn");

????}

????exit(0);

}

?

下面是運行結果。從該結果可以看出,nattch的值隨著共享內(nèi)存狀態(tài)的變化而變化,共享內(nèi)存的值根據(jù)不同的系統(tǒng)會有所不同。

$?./shmem

Create?shared-memory:?753665

/*?在剛創(chuàng)建共享內(nèi)存時(尚未有任何地址映射)共享內(nèi)存的情況?*/

------?Shared?Memory?Segments?--------

key????????shmid??????owner??????perms??????bytes??????nattch?????status??????

0x00000000?753665?????david?????666????????2048???????0???????????????????????

Child:?Attach?shared-memory:?0xb7f59000?/*?共享內(nèi)存的映射地址?*/

Parent:?Attach?shared-memory:?0xb7f59000

/*?在父子進程中進行共享內(nèi)存的地址映射之后共享內(nèi)存的情況*/

------?Shared?Memory?Segments?--------

key????????shmid??????owner??????perms??????bytes??????nattch?????status??????

0x00000000?753665?????david?????666????????2048???????2???????????????????????

Child:?Wait?for?enable?data...

Input?some?string:

Hello?/*?用戶輸入字符串“Hello”?*/

Parent:?Deattach?shared-memory

/*?在父進程中解除共享內(nèi)存的映射關系之后共享內(nèi)存的情況?*/

------?Shared?Memory?Segments?--------

key????????shmid??????owner??????perms??????bytes??????nattch?????status??????

0x00000000?753665?????david?????666????????2048???????1???????????????????????

/*在子進程中讀取共享內(nèi)存的有效數(shù)據(jù)并打印*/

Child:?Shared-memory?:hello

Child:?Deattach?shared-memory

/*?在子進程中解除共享內(nèi)存的映射關系之后共享內(nèi)存的情況?*/

------?Shared?Memory?Segments?--------

key????????shmid??????owner??????perms??????bytes??????nattch?????status??????

0x00000000?753665?????david?????666????????2048???????0???????????????????????

Delete?shared-memory

/*?在刪除共享內(nèi)存之后共享內(nèi)存的情況?*/

------?Shared?Memory?Segments?--------

key????????shmid??????owner??????perms??????bytes??????nattch?????status??????

Finished

相關推薦

電子產(chǎn)業(yè)圖譜

華清遠見(www.farsight.com.cn)是國內(nèi)領先嵌入師培訓機構,2004年注冊于中國北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營分公司。華清遠見除提供嵌入式相關的長期就業(yè)培訓、短期高端培訓、師資培訓及企業(yè)員工內(nèi)訓等業(yè)務外,其下屬研發(fā)中心還負責嵌入式、Android及物聯(lián)網(wǎng)方向的教學實驗平臺的研發(fā)及培訓教材的出版,截止目前為止已公開出版70余本嵌入式/移動開發(fā)/物聯(lián)網(wǎng)相關圖書。企業(yè)理念:專業(yè)始于專注 卓識源于遠見。企業(yè)價值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。