Linux中的程序通訊 共享記憶體

2021-08-28 16:03:26 字數 4750 閱讀 5444

一、什麼是共享記憶體

顧名思義,共享記憶體就是允許兩個不相關的程序訪問同乙個邏輯記憶體。共享記憶體是在兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。不同程序之間共享的記憶體通常安排為同一段物理記憶體。程序可以將同一段共享記憶體連線到它們自己的位址空間中,所有程序都可以訪問共享記憶體中的位址,就好像它們是由用c語言函式malloc分配的記憶體一樣。而如果某個程序向共享記憶體寫入資料,所做的改動將立即影響到可以訪問同一段共享記憶體的任何其他程序。

二、共享記憶體的使得與訊號量一樣,在linux中也提供了一組函式介面用於使用共享記憶體,而且使用共享共存的介面還與訊號量的非常相似,而且比使用訊號量的介面來得簡單。它們宣告在標頭檔案 sys/shm.h中。

1、shmget函式該函式用來建立共享記憶體,它的原型為:

int shmget(key_t key, size_t size, int shm***);第乙個引數,與訊號量的semget函式一樣,程式需要提供乙個引數key(非0整數),它有效地為共享記憶體段命名,shmget函式成功時返回乙個與key相關的共享記憶體識別符號(非負整數),用於後續的共享記憶體函式。呼叫失敗返回-1.

不相關的程序可以通過該函式的返回值訪問同一共享記憶體,它代表程式可能要使用的某個資源,程式對所有共享記憶體的訪問都是間接的,程式先通過呼叫shmget函式並提供乙個鍵,再由系統生成乙個相應的共享記憶體識別符號(shmget函式的返回值),只有shmget函式才直接使用訊號量鍵,所有其他的訊號量函式使用由semget函式返回的訊號量識別符號。

第二個引數,size以位元組為單位指定需要共享的記憶體容量

第三個引數,shm***是許可權標誌,它的作用與open函式的mode引數一樣,如果要想在key標識的共享記憶體不存在時,建立它的話,可以與ipc_creat做或操作。共享記憶體的許可權標誌與檔案的讀寫許可權一樣,舉例來說,0644,它表示允許乙個程序建立的共享記憶體被記憶體建立者所擁有的程序向共享記憶體讀取和寫入資料,同時其他使用者建立的程序只能讀取共享記憶體。

2、shmat函式

第一次建立完共享記憶體時,它還不能被任何程序訪問,shmat函式的作用就是用來啟動對該共享記憶體的訪問,並把共享記憶體連線到當前程序的位址空間。它的原型如下:

void *shmat(int shm_id, const void *shm_addr, int shm***);

第乙個引數,shm_id是由shmget函式返回的共享記憶體標識。

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

第三個引數,shm_***是一組標誌位,通常為0。

呼叫成功時返回乙個指向共享記憶體第乙個位元組的指標,如果呼叫失敗返回-1.

3、shmdt函式

該函式用於將共享記憶體從當前程序中分離。注意,將共享記憶體分離並不是刪除它,只是使該共享記憶體對當前程序不再可用。它的原型如下:

int shmdt(const void *shmaddr);

引數shmaddr是shmat函式返回的位址指標,呼叫成功時返回0,失敗時返回-1.4、shmctl函式與訊號量的semctl函式一樣,用來控制共享記憶體,它的原型如下:int shmctl(int shm_id, int command, struct shmid_ds *buf);

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

第二個引數,command是要採取的操作,它可以取下面的三個值 :

ipc_stat:把shmid_ds結構中的資料設定為共享記憶體的當前關聯值,即用共享記憶體的當前關聯值覆蓋shmid_ds的值。

ipc_set:如果程序有足夠的許可權,就把共享記憶體的當前關聯值設定為shmid_ds結構中給出的值 ipc_rmid:刪除共享記憶體段

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

shmid_ds結構至少包括以下成員:

struct shmid_ds

;三、使用共享記憶體進行程序間通訊

說了這麼多,又到了實戰的時候了。下面就以兩個不相關的程序來說明程序間如何通過共享記憶體來進行通訊。其中乙個檔案shmread.c建立共享記憶體,並讀取其中的資訊,另乙個檔案shmwrite.c向共享記憶體中寫入資料。為了方便操作和資料結構的統一,為這兩個檔案定義了相同的資料結構,定義在檔案shmdata.c中。結構shared_use_st中的written作為乙個可讀或可寫的標誌,非0:表示可讀,0表示可寫,text則是記憶體中的檔案。

shmdata.h的源**如下:

#ifndef _shmdata_h_header

#define _shmdata_h_header

#define text_sz 2048

struct shared_use_st

;#endif

原始檔shmread.c的源**如下:

#include

#include

#include

#include

#include 「shmdata.h」

int main()

//將共享記憶體連線到當前程序的位址空間

shm = shmat(shmid, 0, 0);

if(shm == (void)-1)

printf("\nmemory attached at %x\n", (int)shm); //設定共享記憶體

shared = (struct shared_use_st)shm;

shared->written = 0;

while(running)//讀取共享記憶體中的資料

else

//有其他程序在寫資料,不能讀取資料

sleep(1);

} //把共享記憶體從當前程序中分離

if(shmdt(shm) == -1)

//刪除共享記憶體

if(shmctl(shmid, ipc_rmid, 0) == -1)

exit(exit_success);

}原始檔shmwrite.c的源**如下:

#include

#include

#include

#include

#include

#include 「shmdata.h」

int main()

//將共享記憶體連線到當前程序的位址空間

shm = shmat(shmid, (void)0, 0);

if(shm == (void)-1)

printf(「memory attached at %x\n」, (int)shm); //設定共享記憶體

shared = (struct shared_use_st*)shm;

while(running)//向共享記憶體中寫資料

//向共享記憶體中寫入資料

printf("enter some text: ");

fgets(buffer, bufsiz, stdin);

strncpy(shared->text, buffer, text_sz); //寫完資料,設定written使共享記憶體段可讀

shared->written = 1; //輸入了end,退出迴圈(程式)

if(strncmp(buffer, 「end」, 3) == 0)

running = 0;

} //把共享記憶體從當前程序中分離

if(shmdt(shm) == -1)

sleep(2);

exit(exit_success);

}分析:

1、程式shmread建立共享記憶體,然後將它連線到自己的位址空間。在共享記憶體的開始處使用了乙個結構struct_use_st。該結構中有個標誌written,當共享記憶體中有其他程序向它寫入資料時,共享記憶體中的written被設定為0,程式等待。當它不為0時,表示沒有程序對共享記憶體寫入資料,程式就從共享記憶體中讀取資料並輸出,然後重置設定共享記憶體中的written為0,即讓其可被shmwrite程序寫入資料。

2、程式shmwrite取得共享記憶體並連線到自己的位址空間中。檢查共享記憶體中的written,是否為0,若不是,表示共享記憶體中的資料還沒有被完,則等待其他程序讀取完成,並提示使用者等待。若共享記憶體的written為0,表示沒有其他程序對共享記憶體進行讀取,則提示使用者輸入文字,並再次設定共享記憶體中的written為1,表示寫完成,其他程序可對共享記憶體進行讀操作。

四、關於前面的例子的安全性討論

這個程式是不安全的,當有多個程式同時向共享記憶體中讀寫資料時,問題就會出現。可能你會認為,可以改變一下written的使用方式,例如,只有當written為0時程序才可以向共享記憶體寫入資料,而當乙個程序只有在written不為0時才能對其進行讀取,同時把written進行加1操作,讀取完後進行減1操作。這就有點像檔案鎖中的讀寫鎖的功能。咋看之下,它似乎能行得通。但是這都不是原子操作,所以這種做法是行不能的。試想當written為0時,如果有兩個程序同時訪問共享記憶體,它們就會發現written為0,於是兩個程序都對其進行寫操作,顯然不行。當written為1時,有兩個程序同時對共享記憶體進行讀操作時也是如些,當這兩個程序都讀取完是,written就變成了-1.

要想讓程式安全地執行,就要有一種程序同步的進製,保證在進入臨界區的操作是原子操作。例如,可以使用前面所講的訊號量來進行程序的同步。因為訊號量的操作都是原子性的。

五、使用共享記憶體的優缺點

1、優點:我們可以看到使用共享記憶體進行程序間的通訊真的是非常方便,而且函式的介面也簡單,資料的共享還使程序間的資料不用傳送,而是直接訪問記憶體,也加快了程式的效率。同時,它也不像匿名管道那樣要求通訊的程序有一定的父子關係。

2、缺點:共享記憶體沒有提供同步的機制,這使得我們在使用共享記憶體進行程序間通訊時,往往要借助其他的手段來進行程序間的同步工作。

linux程序通訊 共享記憶體

共享記憶體是ipc機制中的第二個。他允許連個不相關的程序訪問同一塊邏輯記憶體,能夠有效地實現兩個程序間資料傳遞。int shmget key t key,sizr t size,int shm 建立共享記憶體 key為共享記憶體段的命名,size為以位元組為單位的記憶體容量,shm 包含9位元許可權...

Linux程序通訊 共享記憶體

對於linux來講,不同程序之間的記憶體是不能讀寫的,乙個程序只能讀寫自己所屬的記憶體。a程序是不能讀寫b程序記憶體的?如果程式確實想通過記憶體交換資料怎麼辦?linux提供共享記憶體機制。共享記憶體是由核心處於多個程序間交換資訊的目的而留出的一塊記憶體區 段 共享記憶體也需要設定相關許可權的。這段...

Linux程序通訊 共享記憶體

共享記憶體 共享記憶體是一種最為高效的程序間通訊方式,在程序間通訊時核心專門的留出一塊記憶體區。在這段記憶體區可以由訪問程序將其對映到自己的私有位址空間。因此程序就可以直接讀寫這一塊記憶體區,極大的提高了效率。共享記憶體的步驟 1 建立共享記憶體 2 對映貢獻記憶體 原理 相關函式 shmget 建...