多程序通訊(IPC) 共享記憶體

2021-06-20 08:48:34 字數 4962 閱讀 4802

1、共享記憶體介紹

共享記憶體可以說是最有用的程序間通訊方式,也是最快的ipc形式。兩個不同程序a、b共享記憶體的意思是,同一塊物理記憶體被對映到程序a、b各自的程序位址空間。程序a可以即時看到程序b對共享記憶體中資料的更新,反之亦然。由於多個程序共享同一塊記憶體區域,必然需要某種同步機制,互斥鎖和訊號量都可以。採用共享記憶體通訊的乙個顯而易見的好處是效率高,因為程序可以直接讀寫記憶體,而不需要任何資料的拷貝。因此,採用共享記憶體的通訊方式效率是非常高的。

2、應用場景

①程序間通訊-生產者消費者模式

生產者程序和消費者程序通訊常使用共享記憶體,比如乙個網路伺服器,接入程序收到資料報後,直接寫到共享記憶體中,並喚醒處理程序,處理程序從共享記憶體中讀資料報,進行處理。當然,這裡要解決互斥的問題。

②父子程序間通訊

由於fork產生的子程序和父程序不共享記憶體區,所以父子程序間的通訊也可以使用共享記憶體,以posix共享記憶體為例,父程序啟動後使用map_shared建立記憶體對映,並返回指標ptr。fork結束後,子程序也會有指標ptr的拷貝,並指向同乙個檔案對映。這樣父、子程序便共享了ptr指向的記憶體區。

③程序間共享-唯讀模式

業務經常碰到一種場景,程序需要載入乙份配置檔案,可能這個檔案有100k大,那如果這台機器上多個程序都要載入這份配置檔案時,比如有200個程序,那記憶體開銷合計為20m,但如果檔案更多或者程序數更多時,這種對記憶體的消耗就是一種嚴重的浪費。比較好的解決辦法是,由乙個程序負責把配置檔案載入到共享記憶體中,然後所有需要這份配置的程序只要使用這個共享記憶體即可。

3、共享記憶體相關函式詳解

①ftok()函式

獲得乙個id號.

應用說明:

在ipc中,我們經常用用key_t的值來建立或者開啟訊號量,共享記憶體和訊息佇列。

函式原型:

key_t ftok(const char *pathname, int proj_id);

keys:

1)pathname一定要在系統中存在並且程序能夠訪問的

2)proj_id是乙個1-255之間的乙個整數值,典型的值是乙個ascii值。

當成功執行的時候,乙個key_t值將會被返回,否則-1被返回。我們可以使用strerror(errno)來確定具體的錯誤資訊。

考慮到應用系統可能在不同的主機上應用,可以直接定義乙個key,而不用ftok獲得:

#define ipckey 0x344378

②shmget()函式

用來開闢/指向一塊共享記憶體的函式

應用說明:

shmget()用來獲得共享記憶體區域的id,如果不存在指定的共享區域就建立相應的區域。

函式原型:

int shmget(key_t key, size_t size, int shm***);

@key_t key 是這塊共享記憶體的識別符號。如果是父子關係的程序間通訊的話,這個識別符號用ipc_private來代替。如果兩個程序沒有任何關係,所以就用ftok()算出來乙個標         識符(或者自己定義乙個)使用了。

@int size 是這塊記憶體的大小.

@int flag 是這塊記憶體的模式(mode)以及許可權標識。

模式可取如下值:        

ipc_creat 新建(如果已建立則返回目前共享記憶體的id)

ipc_excl   與ipc_creat結合使用,如果已建立則則返回錯誤

然後將「模式」 和「許可權標識」進行「或」運算,做為第三個引數。

如:    ipc_creat | ipc_excl | 0640   

例子中的0666為許可權標識,4/2/1 分別表示讀/寫/執行3種許可權,第乙個0是uid,第乙個6(4+2)表示擁有者的許可權,第二個4表示同組許可權,第3個0表示他人的許可權。

@這個函式成功時返回共享記憶體的id,失敗時返回-1。

關於這個函式,要多說兩句

建立共享記憶體時,shm***引數至少需要 ipc_creat | 許可權標識,如果只有ipc_creat 則申請的位址都是k=0xffffffff,不能使用;

獲取已建立的共享記憶體時,shm***不要用ipc_creat(只能用建立共享記憶體時的許可權標識,如0640),否則在某些情況下,比如用ipcrm刪除共享記憶體後,用該函式並用ipc_creat引數獲取一次共享記憶體(當然,獲取失敗),則即使再次建立共享記憶體也不能成功,此時必須更改key來重建共享記憶體。

③shmat()函式

將這個記憶體區對映到本程序的虛擬位址空間,用來允許本程序訪問一塊共享記憶體的函式。

函式原型:

void *shmat( int shmid , char *shmaddr , int shmflag );

@shmid是那塊共享記憶體的id。

@shmaddr是共享記憶體的起始位址,如果shmaddr為0,核心會把共享記憶體映像到呼叫程序的位址空間中選定位置;如果shmaddr不為0,核心會把共享記憶體映像到shmaddr指定的位  置。所以一般把shmaddr設為0。

@shmflag是本程序對該記憶體的操作模式。如果是shm_rdonly的話,就是唯讀模式。其它的是讀寫模式

@成功時,這個函式返回共享記憶體的起始位址。失敗時返回-1。

④shmdt()函式

刪除本程序對這塊記憶體的使用,shmdt()與shmat()相反,是用來禁止本程序訪問一塊共享記憶體的函式

函式原型:

int shmdt( char *shmaddr );

引數char *shmaddr是那塊共享記憶體的起始位址。

成功時返回0。失敗時返回-1。

⑤shmctl() 函式

控制對這塊共享記憶體的使用

函式原型:

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

int shmid是共享記憶體的id。

int cmd是控制命令,可取值如下:

ipc_stat        得到共享記憶體的狀態

ipc_set         改變共享記憶體的狀態

ipc_rmid        刪除共享記憶體

struct shmid_ds *buf是乙個結構體指標。ipc_stat的時候,取得的狀態放在這個結構體中。如果要改變共享記憶體的狀態,用這個結構體指定。

返回值:        成功:0

失敗:-1

看**

#include #include #include #include #define my_shm_size 1024

int main(int argc, char **argv)

buf = (char *)shmat(shm_id, null, 0);

strcpy(buf, "test shm");

exit(0);

} int status;

wait(&status);

buf = (char *)shmat(shm_id, null, 0);

printf("get shm buf is :%s\n", buf);

shmdt(buf);

return 0;

}

執行結果:

get shm buf is :test shm

解析**:

①共享記憶體在父子程序中公用,直接定義乙個key_t值

②由於父子程序的shm_id不能公用,因此為了保證父子程序公用相同的shm_id,呼叫兩次shm_get,第一次建立一塊共享記憶體,第二次直接返回相同的shm_id

③通過指標buf來獲取到共享記憶體的位址,就可以對這塊共享記憶體為所欲為了。

下面再附上乙個例子,就是利用獲取共享記憶體的開始位址,然後對記憶體任意操作,**我就不解釋了

#include #include #include #include #define my_shm_size 1024

typedef struct info

s_info, *p_info;

int main(int argc, char **argv)

ptr = (int *)shmat(shm_id, null, 0);

*ptr = 3;

ptr++;

s_buf = (p_info)ptr;

strcpy(s_buf->name, "honghong");

s_buf->no = 1;

++s_buf;

strcpy(s_buf->name, "mingming");

s_buf->no = 2;

++s_buf;

strcpy(s_buf->name, "huahua");

s_buf->no = 3;

exit(0);

}int status;

wait(&status);

int *get_ptr;

get_ptr = (int *)shmat(shm_id, null, 0);

printf("counts is %d\n", *get_ptr);

s_buf = (p_info)++get_ptr;

while (s_buf != null && s_buf->no != 0)

if (shmctl(shm_id, ipc_rmid, null) == -1)

return 0;

}

執行結果

counts is 3

get no = 1, name = honghong 

get no = 2, name = mingming 

get no = 3, name = huahua 

多程序通訊 IPC

ipc inter process communication 1 特點 2 主要api 1 建立管道 原型 int pipe int pipefd 2 引數 pipefd 做輸出引數使用,存放是管道的讀,寫檔案描述符。pipefd 0 存放讀,pipefd 1 存放寫 2 讀寫 把將管道當作檔案,...

程序間通訊IPC 共享記憶體

共享記憶體 共享記憶體 就是開闢一段物理記憶體使多個程序共享 是程序間最高效的傳輸方式 共享記憶體必須結合其他方式來實現程序間的同步 程式設計步驟 1 開闢一段共享記憶體 int shmget key t key,size t size,int shm key t key ftok a stat s...

IPC程序間通訊(共享記憶體)

共享記憶體區是最快的ipc形式。一旦這樣的記憶體對映到共享它的程序的位址空間,這些程序間資料傳遞不再涉及到核心,換句話說是程序不再通過執行進入核心的系統呼叫來傳遞彼此的資料。用管道或者訊息佇列傳遞資料,核心為每個ipc物件維護乙個資料結構 用共享記憶體傳遞資料 struct shmid ds inc...