程序通訊之共享記憶體

2021-04-25 14:54:08 字數 3503 閱讀 8763

1. 共享記憶體

1.1. 共享記憶體

共享記憶體是在兩個正在執行的程序之間傳遞資料的一種非常有效的方式。共享記憶體允許兩個不相關的程序訪問同乙個邏輯記憶體。由於它並沒有提供同步機制,所以我們通常需要用其他的機制來同步訪問共享的記憶體。

共享記憶體是由ipc為程序建立的乙個特殊的位址範圍,它將出現在該程序的位址空間中。其他程序可以將同一段共享記憶體連線到它們自己的位址空間中。所有程序都可以訪問共享記憶體的資料,如果乙個程序向共享記憶體寫入了資料,所做的改動將立刻被可以訪問同一段共享記憶體的任何其他程序看到。

核心為每個共享記憶體設定了乙個shmid_ds結構:

struct shmid_ds{

struct ipc_perm  shm_perm;    //see xsi ipc

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 time

time_t        shm_ctime;    // last-change time

為獲得乙個共享記憶體識別符號,呼叫的第乙個函式是shmget。

#include

int shmget(key_t key, size_t size, int flag);

第乙個引數key,與訊號量一樣,它有效地為共享記憶體命名,shmget函式返回乙個共享記憶體的識別符號,該識別符號用於後續的共享記憶體函式。有乙個特殊的鍵值ipc_private(通常是0),作用是建立乙個只屬於建立程序的共享記憶體。

第二個引數size是該共享儲存段的長度(單位:位元組)。如果正在建立乙個新段,則必須指定size;如果正在引用乙個現有的段,則將size指定為0。當建立乙個新段時,段內的內容初始化為0。

第三個引數flag包含九個位元許可權標誌,其作用類似於檔案的訪問許可權。它們可以與值ipc_creat做按位或操作以建立乙個新的共享記憶體段。即使設定了ipc_creat標誌,給出的鍵是乙個已經有訊號量的鍵也不會產生錯誤。只有聯合使用ipc_creat和ipc_excl來確保建立出的是乙個新的唯一的共享記憶體段,如果該共享記憶體段存在,就返回乙個錯誤(errno設定為eexsit)。

如果共享記憶體建立成功,shmget返回乙個非負整數(共享記憶體識別符號);如果失敗,則返回-1。

函式shmctl對其共享記憶體執行多種操作。

#include

int shmget(int shmid, int cmd, struct shmid_ds *buf);

第乙個引數shmid是shmget返回的共享記憶體識別符號。

第二個引數cmd是要執行的操作,有下列五種命令:

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_nattch欄位),所以除非使用該段的最後乙個程序終止或與該段脫接,否則不會實際上刪除該記憶體段。這種刪除立即生效,所以不能再用shmat與該段連線。此命令只能由下列兩種程序執行:一種是其有效使用者id等於shm _perm.cuid或shm _perm.uid;另一種是具有超級使用者特權的程序。

shm_lock 將共享記憶體段鎖定在記憶體中。此命令只能由超級使用者執行。

shm_unlock 解鎖共享記憶體段。此命令只能由超級使用者執行。

第三個引數buf是乙個指標,它指向包含共享記憶體模式和訪問許可權的shmid_ds結構。

如果成功,shmctl返回0;如果失敗,則返回-1。

一旦建立了乙個共享記憶體段,程序就可呼叫shmat將其連線它的位址空間中。

#include

int shmat(int shmid, const void *addr, int flag);

第乙個引數shmid是shmget返回的共享記憶體識別符號。

第二個引數addr指定的是共享記憶體連線到當前程序中的位址位置。它通常是乙個空指標,表示讓系統來選擇共享記憶體出現的位址。

2). 如果addr非0,並且沒有指定shm_rnd,則此段連線到addr指定的位址上。

3). 如果addr非0,並且指定shm_rnd,則此段連線到(addr - (addr mod ulus shmlba ))指定的位址上。shm_rnd命令的意思是"取整"。shmlba的意思是"低邊界位址倍數",它總是2的乘方。該算式是將位址向下取最近的1個shmlba的倍數。

第四個引數flag是一組標誌。它可能有兩個取值是shm_rnd(這個與shm_addr聯合使用,用來控制共享內連線的位址)和shm_rdonly(它使得連線的記憶體為唯讀)

如果shmat呼叫成功,返回的是該段所連線的實際位址,如果出錯,返回-1。如果執行成功,則核心使該共享記憶體段shmid_ds結構中的shm_nattch計數器加一。

共享記憶體的讀寫許可權由它的屬主(共享記憶體的建立者)、它的訪問許可權和當前程序的屬主決定。有個規則例外:當flag&shm_rdonly為真時,此時即使該共享記憶體的訪問許可權允許寫操作,它都不能被寫入。

當對共享記憶體段的操作已經結束時,則呼叫shmdt脫接該段。

#include

int shmdt(void *addr);

第乙個引數是以前呼叫shmat時的返回值。

如果成功,shmdt將使相關shmid_ds結構的shm_nattch計數器值減一。

注意:這並不是從系統中刪除其識別符號及其資料結構。該識別符號仍然存在,直到某個程序呼叫shmctl(帶命令ipc_rmid)特定的刪除它。

1.2. 例項

我們希望熟悉這些函式後,能夠聯絡它們。下面將是兩個程式:乙個是消費者,將建立乙個共享記憶體段,然後吧寫到裡面的資料都顯示出來;另乙個是生產者,將連線乙個已經存在的共享記憶體段,並允許先其中輸入資料。

第乙個程式,在共享記憶體的開始處使用了乙個結構share_data_seg_s。該結構中有乙個標誌writtenflag,當共享記憶體有資料寫入時,就設定該標誌。這個標誌被設定時,程式就從共享記憶體中讀取文字,將列印出來,然後清除這個標誌已經讀完資料。收到字串"end"退出迴圈。最後,程式分離共享記憶體段並刪除它。

第二個程式,獲得共享記憶體識別符號,鏈結到同乙個共享記憶體段。然後使用者輸入字串。如果標誌writtenflag被設定,就知道第乙個程式沒有讀完上一次資料,因此就繼續等待。當其它程序清除了這個標誌後,就寫入新資料並設定該標誌。寫入字串"end"終止並分離共享記憶體段。

源程式如下:

程序通訊之共享記憶體

程序通訊之共享記憶體 在通訊的程序之間存在一塊可直接訪問的共享空間,通過對這片共享空間進行寫 讀操作實現程序之間的資訊交換。共享儲存是程序通訊中最靈活,速度最快的通訊方式。因為掛接到同一塊記憶體區域的兩個程序可以直接訪問記憶體區域。而其他幾種方式需要拷貝到核心,再從核心拷貝出去,進行通訊。需要注意的...

程序間通訊之共享記憶體

此程式實現兩個普通程序間通過共享記憶體來進行通訊,共享記憶體能夠進行大資料量的通訊,這一點事訊息佇列無法比擬的。在這裡同時使用了訊號量來保證兩個程序間的讀寫同步。傳送端源 include include include include include include include include ...

Linux程序通訊之共享記憶體

一 建立共享記憶體,使用shmget函式 int shmget key tkey,int size,int shm 返回值 如果成功,返回共享記憶體段識別符號。如果失敗,則返回 1 errno einval 無效的記憶體段大小 eexist 記憶體段已經存在,無法建立 eidrm 記憶體段已經被刪除...