加入星計(jì)劃,您可以享受以下權(quán)益:

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

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

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

?

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

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

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

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

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

1.函數(shù)說(shuō)明

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

2.函數(shù)格式

表8.20列舉了shmget()函數(shù)的語(yǔ)法要點(diǎn)。

表8.20 shmget()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#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)存的鍵值,多個(gè)進(jìn)程可以通過(guò)它訪(fǎng)問(wèn)同一個(gè)共享內(nèi)存,其中有個(gè)特殊值IPC_PRIVATE。它用于創(chuàng)建當(dāng)前進(jìn)程的私有共享內(nèi)存

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

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

函數(shù)返回值

成功:共享內(nèi)存段標(biāo)識(shí)符

出錯(cuò):-1

表8.21列舉了shmat()函數(shù)的語(yǔ)法要點(diǎn)。

表8.21 shmat()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#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ū)標(biāo)識(shí)符

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

shmflg?

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

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

函數(shù)返回值

成功:被映射的段地址

出錯(cuò):-1

表8.22列舉了shmdt()函數(shù)的語(yǔ)法要點(diǎn)。

表8.22 shmdt()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

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

函數(shù)原型

int?shmdt(const?void?*shmaddr)

函數(shù)傳入值

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

函數(shù)返回值

成功:0

出錯(cuò):-1

?

3.使用實(shí)例

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

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

最后在子進(jìn)程中刪除共享內(nèi)存。因?yàn)楣蚕韮?nèi)存自身并不提供同步機(jī)制,所以應(yīng)該額外實(shí)現(xiàn)不同進(jìn)程之間的同步(例如:信號(hào)量)。為了簡(jiǎn)單起見(jiàn),在本實(shí)例中用標(biāo)志字符串來(lái)實(shí)現(xiàn)非常簡(jiǎn)單的父子進(jìn)程之間的同步。

這里要介紹的一個(gè)命令是ipcs,這是用于報(bào)告進(jìn)程間通信機(jī)制狀態(tài)的命令。它可以查看共享內(nèi)存、消息隊(duì)列等各種進(jìn)程間通信機(jī)制的情況,這里使用了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)?/*?子進(jìn)程處理?*/

????{

????????/*映射共享內(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");

????????

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

父進(jìn)程已經(jīng)向共享內(nèi)存寫(xiě)入有效數(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?/*?父進(jìn)程處理?*/

????{

????????/*映射共享內(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);

}

?

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

$?./shmem

Create?shared-memory:?753665

/*?在剛創(chuàng)建共享內(nèi)存時(shí)(尚未有任何地址映射)共享內(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

/*?在父子進(jìn)程中進(jìn)行共享內(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?/*?用戶(hù)輸入字符串“Hello”?*/

Parent:?Deattach?shared-memory

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

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

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

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

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

Child:?Shared-memory?:hello

Child:?Deattach?shared-memory

/*?在子進(jìn)程中解除共享內(nèi)存的映射關(guān)系之后共享內(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

相關(guān)推薦

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

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