亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

進程間通信之共享存儲

2024-06-28 13:27:52
字體:
來源:轉載
供稿:網友
進程間通信之共享存儲

共享存儲允許兩個或更多進程共享一個給定的存儲區。因為數據不需要在客戶進程和服務器進程之間復制,所以這是最快的一種ipC。使用共享存儲時要掌握的唯一竅門是多個進程之間對一個給定存儲區的同步訪問。若服務器進程正在將數據放入共享存儲區,則在它做完這一操作之前,客戶進程不應當去取這些數據。通常,信號量被用來實現對共享存儲訪問的同步。(記錄鎖也可以用于這種場合。)

內核為每個共享存儲段設置了一個shmid_ds結構。

struct shmid_ds {    struct ipc_perm    shm_perm;        size_t             shm_segsz;       /* size of segment in bytes */    pid_t              shm_lpid;        /* pid of last shmop() */    pid_t              shm_cpid;        /* pid of creator */    shmatt_t           shm_nattch;      /* number of current attaches */    time_t             shm_atime;       /* last-attach time */    time_t             shm_dtime;       /* last-detach tiime */    time_t             shm_ctime;       /* last-change time */    ...};

(按照支持共享存儲段的需要,每種實現會在shmid_ds結構中增加其他成員。)

shmatt_t類型定義為不帶符號整型,它至少與unsigned short一樣大。

 為獲得一個共享存儲標識符,調用的第一個函數通常是shmget。

#include <sys/shm.h>int shmget(key_t key, size_t size, int flag);返回值:若成功則返回共享存儲ID,若出錯則返回-1

http://www.CUOXin.com/nufangrensheng/p/3561681.html中標識符和鍵部分,說明了將key變換為標識符的規則,討論了是否創建一個新集合,或是引用一個現存集合。

當創建一個新段時,初始化shmid_ds結構的下列成員:

  • ipc_perm結構按http://www.CUOXin.com/nufangrensheng/p/3561681.html中權限結構所述進行初始化。該結構中mode成員按flag中的相應權限位設置。這些權限用http://www.CUOXin.com/nufangrensheng/p/3561681.html表15-2中的常量指定。
  • shm_lpid、shm_nattach、shm_atime、以及shm_dtime都設置為0。
  • shm_ctime設置為當前時間。
  • shm_segsz設置為請求的長度(size)。

參數size是該共享存儲段的長度(單位:字節)。實現通常將其向上取為系統頁長的整數倍。但是,若應用指定的size值并非系統頁長的整數倍,那么最后一頁的余下部分是不可使用的。如果正在創建一個新段(一般是在服務器進程中),則必須指定其size。如果正在引用一個現存的段(一個客戶進程),則將size指定為0。當創建一新段時,段內的內容初始化為0。

shmctl函數對共享存儲段執行多種操作。

#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);返回值:若成功則返回0,若出錯則返回-1

cmd參數指定下列5中命令中一種,使其在shmid指定的段上執行。

IPC_STAT    取此段的shmid_ds結構,并將它存放在由buf指向的結構中。

IPC_SET      按buf指向結構中的值設置與此段相關結構中的下列三個字段:shm_perm.uid、shm_perm.gid以及shm_perm.mode。此命令只能由下列兩種進程執行:一種是其有效用戶ID等于shm_perm.cuid或shm_perm.uid的進程;另一種是具有超級用戶特權的進程。

IPC_RMID    從系統中刪除該共享存儲段。因為每個共享存儲段有一個連接計數(shmid_ds結構中的shm_nattach字段),所以除非使用該段的最后一個進程終止或與該段脫節,否則不會實際上刪除該存儲段。不管此段是否仍在使用,該段標識符立即被刪除,所以不能再用shmat與該段連接。此命令只能由下列兩種進程執行:一種是其有效用戶ID等于shm_perm.cuid或shm_perm.uid的進程,另一種是具有超級用戶特權的進程。

linux和Solaris提供了下列另外兩種命令,但它們并非Single UNIX Specification的組成部分:

SHM_LOCK        將共享存儲段鎖定在內存中。此命令只能由超級用戶執行。

SHM_UNLOCK    解鎖共享存儲段。此命令只能由超級用戶執行。

一旦創建了一個共享存儲段,進程就可調用shmat將其連接到它的地址空間中。

#include <sys/shm.h>void *shmat(int shmid, const void *addr, int flag);返回值:若成功則返回指向共享存儲的指針,若出錯則返回-1

共享存儲段連接到調用進程的哪個地址上與addr參數以及在flag中是否指定SHM_RND位有關。

  • 如果addr為0,則此段連接到由內核選擇的第一個可用地址上。這是推薦的使用方式。
  • 如果addr非0,并且沒有指定SHM_RND,則此段連接到addr所指定的地址上。
  • 如果addr非0,并且指定了SHM_RND,則此段連接到(addr-(addr mod ulus SHMLBA))所表示的地址上。SHM_RND命令的意思是“取整”。SHMLBA的意思是“低邊界地址倍數”,它總是2的乘方。該算式是將地址向下取最近1個SHMLBA的倍數。

除非只計劃在一種硬件上運行應用程序(這在當今是不大可能的),否則不應指定共享段所連接到的地址。所以一般應指定addr為0,以便由內核選擇地址。

如果在flag中指定了SHM_RDONLY位,則以只讀方式連接此段。否則以讀寫方式連接此段。

shmat的返回值是該段所連接的實際地址,如果出錯則返回-1。如果shmat成功執行,那么內核將使該共享存儲段shmid_ds結構中的shm_nattach計數器值加1.

當對共享存儲段的操作已經結束時,則調用shmdt脫接該段。注意,這并不從系統中刪除其標識符以及數據結構。該標識符仍然存在,直至某個進程(一般是服務器進程)調用shmctl(帶命令IPC_RMID)特地刪除它。

#include <sys/shm.h>int shmdt(void *addr);返回值:若成功則返回0,若出錯則返回-1

addr參數是以前調用shmat時的返回值。如果成功,shmdt將使相關shmid_ds結構中的shm_nattach計數器值減1。

實例

內核將以addr=0連接的共享存儲段放在什么位置上與系統密切相關。程序清單15-11打印以寫信息,它們與特定系統將各種不同類型的數據放在什么位置有關。

程序清單15-11 打印各種不同類型的數據所存放的位置

#include "apue.h"#include <sys/shm.h>#define ARRAY_SIZE    40000#define MALLOC_SIZE    100000#define SHM_SIZE    100000#define SHM_MODE    0600    /* user read/write */char    array[ARRAY_SIZE];    /* uninitialized data = bss */int main(void){    int     shmid;    char    *ptr, *shmptr;        PRintf("array[] from %lx to %lx/n", (unsigned long)&array[0],         (unsigned long)&array[ARRAY_SIZE]);    printf("stack aound %lx/n", (unsigned long)&shmid);        if((ptr = malloc(MALLOC_SIZE)) == NULL)        err_sys("malloc error");    printf("malloced from %lx to %lx/n", (unsigned long)ptr,         (unsigned long)ptr+MALLOC_SIZE);    if((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0)        err_sys("shmget error");    if((shmptr = shmat(shmid, 0, 0)) == (void *)-1)        err_sys("shmat error");    printf("shared memory attched from %lx to %lx/n",        (unsigned long)shmptr, (unsigned long)shmptr+SHM_SIZE);    if(shmctl(shmid, IPC_RMID, 0) < 0)        err_sys("shmctl error");    exit(0);}

本人系統上運行此程序,根據輸出結果可以描繪存儲區大致分布,發現它與http://www.CUOXin.com/nufangrensheng/p/3508169.html中的圖7-3中所示的典型存儲區布局類似。

http://www.CUOXin.com/nufangrensheng/p/3559664.html中曾說明mmap函數可將一個文件的若干部分映射至進程地址空間。這在概念上類似與用shmat XSI IPC函數連接一共享存儲段。兩者之間的主要區別是:用mmap映射的存儲段是與文件相關聯的,而XSI共享存儲段則并無這種關聯。

實例:/dev/zero的存儲映射

共享存儲可由不相關的進程使用。但如果進程是相關的,則某些實現提供了一種不同的技術。

在讀設備/dev/zero時,該設備是0字節的無限資源。它也接收寫向它的任何數據。但又忽略這些數據。我們對此設備作為IPC的興趣在于,當對其進行存儲映射時,它具有一些特殊的性質:

  • 創建一個無名(unnamed)存儲區,其長度是mmap的第二個參數,將其向上取整為系統的最近頁長。
  • 存儲區都初始化為0.
  • 如果多個進程的共同祖先進程對mmap指定了MAP_SHARED標志,則這些進程可共享此存儲區。

程序清單15-12 在父、子進程間使用/dev/zero存儲映射I/O的IPC

#include "apue.h"#include <fcntl.h>#include <sys/mman.h>#define NLOOPS    1000#define SIZE      sizeof(long);    /* size of shared memory area */static intupdate(long *ptr){    return((*ptr)++);    /* return value before increment */}intmain(void){    int      fd, i, counter;    pid_t    pid;        void     *area;    if((fd = open("/dev/zero", O_RDWR)) < 0)        err_sys("open error");    if((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)        err_sys("mmap error");    close(fd);    /* can close /dev/zero now that it's mapped */TELL_WAIT();    if((pid = fork()) < 0)    {        err_sys("fork error");    }    else if(pid > 0)    /* parent */    {        for(i=0; i<NLOOPS; i+=2)        {            if((counter = update((long *)area)) != i)                err_quit("parent: expected %d, got %d", i, counter);            TELL_CHILD(pid);            WAIT_CHILD();        }    }    else    {        for(i = 1; i < NLOOPS + 1; i += 2)        {            WAIT_PARENT();            if((counter = update((long *)area)) != i)                err_quit("child: expected %d, got %d", i, counter);            TELL_PARENT(getppid());        }    }    exit(0);}

它打開此/dev/zero設備,然后指定長整型的長度調用mmap。注意,一旦存儲區映射成功,就關閉此設備。然后,進程創建一個子進程。因為在調用mmap時指定了MAP_SHARED,所以一個進程寫到存儲映射區的數據可由另一個進程見到。(如果已指定MAP_PRIVATE,則此示例程序不能工作)

然后,父、子進程交替運行,使用http://www.CUOXin.com/nufangrensheng/p/3510306.html中的同步函數各自對共享存儲映射區中的長整型數加1。存儲映射區由mmap初始化為0。父進程先對它進行增1操作,使其成為1,然后子進程對其進程增1操作,使其成為2,然后父進程使其成為3......注意,當在update函數中對長整型值增1時,因為增加的是其值,而不是指針,所以必須使用括號。

以上述方式使用/dev/zero的優點是:在調用mmap創建映射區之前,無需存在一個實際文件。映射/dev/zero自動創建一個指定長度的映射區。這種技術的缺點是:它只在相關進程間起作用。但在相關進程之間使用線程可能更為簡單、有效。注意,無論使用哪一種技術,都需對共享數據進行同步訪問。

實例:匿名存儲映射

很多實現提供了一種類似于/dev/zero的設施,稱為匿名存儲映射。為了使用這種功能,在調用mmap時指定MAP_ANON標志,并將文件描述符指定為-1。結果得到的區域是匿名的(因為它并不通過一個文件描述符與一個路徑名相結合),并且創建一個可與后代進程共享的存儲區。

注意,Linux為此定義了MAP_ANONYMOUS標志,并將MAP_ANON標志定義為與它相同的值以改善應用的可移植性。

為使程序清單15-12所示的程序應用這種特征,對它做了三處修改:一是刪除了對于/dev/zero的open語句;二是刪除了對于fd的close語句;三是將mmap調用修改成:

if((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)

的形式。在此調用中,指定了MAP_ANON標志,并將文件描述符取為-1。程序的其余部分則沒有改變。

最后兩個例子說明了在多個相關進程之間如何使用共享存儲段。如果在無關進程之間使用共享存儲段,那么有兩種替換的方法。其一是應用程序使用XSI共享存儲函數;另一種是使用mmap將同一文件映射至它們的地址空間,為此使用MAP_SHARED標志。

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品免费观看在线| 欧美日韩国产精品一区二区不卡中文| 亚洲精品一区二区在线| 国产精品99免视看9| 亚洲专区中文字幕| 97视频在线观看免费高清完整版在线观看| 国产精品日韩精品| 久久久久久久97| 日韩免费观看在线观看| 久久精品国产欧美亚洲人人爽| 成人动漫网站在线观看| 久久久噜噜噜久久中文字免| 亚洲成人xxx| 美女黄色丝袜一区| 久久色在线播放| 国产视频久久久久久久| 第一福利永久视频精品| 亚洲欧美精品一区| 亚洲精品国产精品国自产观看浪潮| 久久久精品久久久| 国产精品久久久久久中文字| 91精品视频观看| 在线丨暗呦小u女国产精品| 亚洲精品suv精品一区二区| 久久久精品国产亚洲| 日韩大片在线观看视频| 日韩免费在线免费观看| 欧美日韩电影在线观看| 国产日韩欧美自拍| 亚洲97在线观看| 亚洲精品成人久久电影| 91色视频在线观看| 国产女人18毛片水18精品| 最新国产成人av网站网址麻豆| 国产精品久久久久久久久久东京| 中文字幕欧美专区| 欧美亚洲在线视频| 国产精品色婷婷视频| 欧美孕妇与黑人孕交| 色琪琪综合男人的天堂aⅴ视频| 国模精品一区二区三区色天香| 亚洲xxxxx电影| 欧美尤物巨大精品爽| 亚洲人成伊人成综合网久久久| 一区二区三区www| 亚洲激情第一页| 98精品在线视频| 亚洲人成77777在线观看网| 97视频在线观看播放| 日韩av一区在线观看| 亚洲国产精品视频在线观看| 日韩欧美一区二区在线| 久久久久久久国产精品| 成人精品一区二区三区| 色综合久久悠悠| 91精品久久久久久久久久另类| 国产精品成人av性教育| 日韩成人在线视频| 日韩风俗一区 二区| 亚洲福利视频在线| 日韩av电影在线免费播放| 久久精品夜夜夜夜夜久久| 亚洲va久久久噜噜噜| 日韩亚洲国产中文字幕| 亚洲日本欧美中文幕| 国产免费成人av| 国产婷婷97碰碰久久人人蜜臀| 日韩免费在线播放| 日韩影视在线观看| 亚洲精品一区二区久| 国产精品成人v| 国产精品视频26uuu| 日韩视频一区在线| 日本精品一区二区三区在线| 日韩不卡在线观看| 亚洲视频日韩精品| 亚洲精品日韩久久久| 九色精品免费永久在线| 亚洲国产精品女人久久久| 91久久久久久久久久久久久| 最近2019年日本中文免费字幕| 日韩av快播网址| 中文字幕日韩有码| 久久久999精品视频| 亚洲999一在线观看www| 国产精品久久77777| 久青草国产97香蕉在线视频| 7m精品福利视频导航| 国产精品自拍偷拍视频| 日韩中文字幕在线免费观看| 亚洲免费人成在线视频观看| 欧美日韩加勒比精品一区| 欧美综合一区第一页| 成人激情在线播放| 日韩av在线看| 韩国三级电影久久久久久| 亚洲一区精品电影| 日本一区二区在线播放| 91精品久久久久久久久| 欧美日韩精品在线播放| 久久免费精品视频| 久久综合九色九九| 日韩经典一区二区三区| 欧美另类在线播放| 在线观看日韩www视频免费| 久久久精品欧美| 久久伊人精品一区二区三区| 久久精品91久久香蕉加勒比| y97精品国产97久久久久久| 国产精品久久久亚洲| 欧美大片在线看| 懂色av影视一区二区三区| 亚洲精品久久在线| 亚洲第一天堂av| 91成人在线播放| 国产精品亚发布| 亚洲欧美激情精品一区二区| 欧美激情中文字幕乱码免费| 国产成人综合久久| 中文字幕亚洲综合久久| 国内免费久久久久久久久久久| 亚洲直播在线一区| 国产精品自产拍在线观| 亚洲网站在线播放| 亚洲精品大尺度| 最近2019中文字幕在线高清| 国产精品欧美久久久| 国产精品青草久久久久福利99| 九九热r在线视频精品| 久久久噜噜噜久噜久久| 日韩在线观看网站| 欧美床上激情在线观看| 亚洲日韩欧美视频一区| 日韩精品中文字幕在线观看| 国产精品无码专区在线观看| 亚洲一区二区三区xxx视频| 国产91色在线| 欧洲亚洲免费视频| 欧美日韩亚洲视频| 国产精品永久免费在线| 成人观看高清在线观看免费| 亚洲第一精品福利| 成人字幕网zmw| 岛国av一区二区三区| 久久av.com| 欧美大片欧美激情性色a∨久久| 欧美日韩一区二区三区在线免费观看| 精品国产一区二区三区久久| 日韩久久免费视频| 欧美精品成人在线| 日韩一区二区三区国产| 超碰日本道色综合久久综合| 亚洲欧美一区二区精品久久久| 久久久久五月天| 成人黄色网免费| 精品无码久久久久久国产| 激情亚洲一区二区三区四区| 久久久免费av| www日韩中文字幕在线看| 亚州av一区二区| 精品亚洲一区二区三区在线观看| 人九九综合九九宗合| 神马久久桃色视频| 亚洲精品视频免费在线观看|