1. 程式人生 > >程序間通訊——共享記憶體(Shared Memory)

程序間通訊——共享記憶體(Shared Memory)

共享記憶體是System V版本的最後一個程序間通訊方式。共享記憶體,顧名思義就是允許兩個不相關的程序訪問同一個邏輯記憶體,共享記憶體是兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。不同程序之間共享的記憶體通常為同一段實體記憶體。程序可以將同一段實體記憶體連線到他們自己的地址空間中,所有的程序都可以訪問共享記憶體中的地址。如果某個程序向共享記憶體寫入資料,所做的改動將立即影響到可以訪問同一段共享記憶體的任何其他程序。

特別提醒:共享記憶體並未提供同步機制,也就是說,在第一個程序結束對共享記憶體的寫操作之前,並無自動機制可以阻止第二個程序開始對它進行讀取,所以我們通常需要用其他的機制來同步對共享記憶體的訪問,例如訊號量


下面就 Shared Memory 的IPC作以闡述與分析。

共享記憶體的通訊原理

Linux中,每個程序都有屬於自己的程序控制塊(PCB)地址空間(Addr Space),並且都有一個與之對應的頁表,負責將程序的虛擬地址與實體地址進行對映,通過記憶體管理單元(MMU)進行管理。兩個不同的虛擬地址通過頁表對映到物理空間的同一區域,它們所指向的這塊區域即共享記憶體

共享記憶體的通訊原理示意圖:

對於上圖我的理解是:當兩個程序通過頁表將虛擬地址對映到實體地址時,在實體地址中有一塊共同的記憶體區,即共享記憶體,這塊記憶體可以被兩個程序同時看到。這樣當一個程序進行寫操作,另一個程序讀操作就可以實現程序間通訊。但是,我們要確保一個程序在寫的時候不能被讀,因此我們使用訊號量

來實現同步與互斥。

對於一個共享記憶體,實現採用的是引用計數的原理,當程序脫離共享儲存區後,計數器減一,掛架成功時,計數器加一,只有當計數器變為零時,才能被刪除。當程序終止時,它所附加的共享儲存區都會自動脫離。

為什麼共享記憶體速度最快?

藉助上圖說明:Proc A 程序給記憶體中寫資料, Proc B 程序從記憶體中讀取資料,在此期間一共發生了兩次複製

(1)Proc A 到共享記憶體       (2)共享記憶體到 Proc B

因為直接在記憶體上操作,所以共享記憶體的速度也就提高了。

共享記憶體的介面函式以及指令

1.檢視系統中的共享儲存段

ipcs -m

2.刪除系統中的共享儲存段

ipcrm -m [shmid]

3.shmget ( ):建立共享記憶體

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

[引數key]:由ftok生成的key標識,標識系統的唯一IPC資源。

[引數size]:需要申請共享記憶體的大小。在作業系統中,申請記憶體的最小單位為頁,一頁是4k位元組,為了避免記憶體碎片,我們一般申請的記憶體大小為頁的整數倍。

[引數shmflg]:如果要建立新的共享記憶體,需要使用IPC_CREAT,IPC_EXCL,如果是已經存在的,可以使用IPC_CREAT或直接傳0。

[返回值]:成功時返回一個新建或已經存在的的共享記憶體識別符號,取決於shmflg的引數。失敗返回-1並設定錯誤碼。

4.shmat ( ):掛接共享記憶體

void *shmat(int shmid, const void *shmaddr, int shmflg);

[引數shmid]:共享儲存段的識別符號。

[引數*shmaddr]:shmaddr = 0,則儲存段連線到由核心選擇的第一個可以地址上(推薦使用)。

[引數shmflg]:若指定了SHM_RDONLY位,則以只讀方式連線此段,否則以讀寫方式連線此段。

[返回值]:成功返回共享儲存段的指標(虛擬地址),並且核心將使其與該共享儲存段相關的shmid_ds結構中的shm_nattch計數器加1(類似於引用計數);出錯返回-1。

5.shmdt ( ):去關聯共享記憶體

當一個程序不需要共享記憶體的時候,就需要去關聯。該函式並不刪除所指定的共享記憶體區,而是將之前用shmat函式連線好的共享記憶體區脫離目前的程序。

int shmdt(const void *shmaddr);

[引數*shmaddr]:連線以後返回的地址。

[返回值]:成功返回0,並將shmid_ds結構體中的 shm_nattch計數器減1;出錯返回-1。

6.shmctl ( ):銷燬共享記憶體

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

[引數shmid]:共享儲存段識別符號。

[引數cmd]:指定的執行操作,設定為IPC_RMID時表示可以刪除共享記憶體。

[引數*buf]:設定為NULL即可。

[返回值]:成功返回0,失敗返回-1。

模擬共享記憶體

我們用server來建立共享儲存段,用client獲取共享儲存段的識別符號,二者關聯起來之後server將資料寫入共享儲存段,client從共享區讀取資料。通訊結束之後server與client斷開與共享區的關聯,並由server釋放共享儲存段。

comm.h

//comm.h
#ifndef _COMM_H__
#define _COMM_H__

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

#define PATHNAME "."
#define PROJ_ID 0x6666

int CreateShm(int size);
int DestroyShm(int shmid);
int GetShm(int size);
#endif

comm.c

//comm.c
#include"comm.h"

static int CommShm(int size,int flags)
{
	key_t key = ftok(PATHNAME,PROJ_ID);
	if(key < 0)
	{
		perror("ftok");
		return -1;
	}
	int shmid = 0;
	if((shmid = shmget(key,size,flags)) < 0)
	{
		perror("shmget");
		return -2;
	}
	return shmid;
}
int DestroyShm(int shmid)
{
	if(shmctl(shmid,IPC_RMID,NULL) < 0)
	{
		perror("shmctl");
		return -1;
	}
	return 0;
}
int CreateShm(int size)
{
	return CommShm(size,IPC_CREAT | IPC_EXCL | 0666);
}
int GetShm(int size)
{
	return CommShm(size,IPC_CREAT);
}

client.c

//client.c
#include"comm.h"

int main()
{
	int shmid = GetShm(4096);
	sleep(1);
	char *addr = shmat(shmid,NULL,0);
	sleep(2);
	int i = 0;
	while(i < 26)
	{
		addr[i] = 'A' + i;
		i++;
		addr[i] = 0;
		sleep(1);
	}
	shmdt(addr);
	sleep(2);
	return 0;
}

server.c

//server.c
#include"comm.h"

int main()
{
	int shmid = CreateShm(4096);

	char *addr = shmat(shmid,NULL,0);
	sleep(2);
	int i = 0;
	while(i++ < 26)
	{
		printf("client# %s\n",addr);
		sleep(1);
	}
	shmdt(addr);
	sleep(2);
	DestroyShm(shmid);
	return 0;
}

Makefile

//Makefile
.PHONY:all
all:server client

client:client.c comm.c
	gcc -o [email protected] $^
server:server.c comm.c
	gcc -o [email protected] $^

.PHONY:clean
clean:
	rm -f client server

執行結果:


總結:

(1)優點:我們可以看到使用共享記憶體進行程序之間的通訊是非常方便的,而且函式的介面也比較簡單,資料的共享還使程序間的資料不用傳送,而是直接訪問記憶體,加快了程式的效率。

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


相關推薦

程序通訊——共享記憶體Shared Memory簡易原理和建立_獲得函式

共享記憶體是System V版本的最後一個程序間通訊方式。共享記憶體,顧名思義就是允許兩個不相關的程序訪問同一個邏輯記憶體,共享記憶體是兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。不同程序之間共享的記憶體通常為同一段實體記憶體。程序可以將同一段實體記憶體連線到他們自己的地址空間中,所有

程序通訊——共享記憶體Shared Memory

共享記憶體是System V版本的最後一個程序間通訊方式。共享記憶體,顧名思義就是允許兩個不相關的程序訪問同一個邏輯記憶體,共享記憶體是兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。不同程序之間共享的記憶體通常為同一段實體記憶體。程序可以將同一段實體記憶體連線到他

程序通訊共享記憶體Share Memory

為了實現多個程序之間的通訊,我們可以用系統頁面檔案來作為共享記憶體檔案。 1.首先我們建立第一個程序,用系統函式CreateFileMapping建立共享記憶體檔案,用函式MapViewOfFile

php程序通訊--共享記憶體

php如何實現共享記憶體。(注意:本示例是在linux下,請勿在windows下嘗試此程式碼,並且必須是在php-cli模式下) php提供了兩種實現共享記憶體的擴充套件。下面我們來一一講解。   一、shmop 系類函式 <?php $shm_key = ftok(__FILE

Linux關於程序通訊共享記憶體

共享記憶體概念 共享記憶體允許兩個不相關的程序去訪問同一部分邏輯記憶體 如果需要在兩個執行中的程序之間傳輸資料,共享記憶體將是一種效率極高的解決方案 共享記憶體是由IPC為一個程序建立的一個特殊的地址範圍,它將出現在程序的地址空間中。 其他程序可以把同一段共享記憶體段“連

程序通訊--共享記憶體

共享記憶體 當一個程式想和另外一個程式通訊的時候,那記憶體將會為這兩個程式生成一塊公共的記憶體區域。這塊被兩個程序分享的記憶體區域叫做共享記憶體 共享記憶體是程序間通訊最簡單的一種,共享記憶體允許兩個或更多程序訪問同一塊記憶體,就如同 malloc() 函式向不

程序通訊---共享記憶體

一、IPC(Inter-Process Communication,程序間通訊)物件的介紹 System V 的IPC物件有共享記憶體、訊息佇列、訊號燈。 注意:在IPC的通訊模式下,不管是使用訊息佇列還是共享記憶體,甚至是訊號燈,每個IPC的物件都有唯一的名

Windows程序通訊-共享記憶體

#include "stdafx.h" #include "windows.h" //Name given to the pipe #define g_szPipeName "\\\\.\\Pipe\\MyNamedPipe" //Pipe name format - \\.\pipe\pipename

程序程式設計之程序通訊-共享記憶體,訊號量和套接字

1. 背景 本文將介紹程序通訊中的訊號量,共享記憶體和套接字方法。 2. 訊號量 2.1 訊號量的定義 為了防止出現因多個程式同時訪問一個共享資源而引發的一系列問題,我們需要一種方法,它可以通過生成並使用令牌來授權,在任一時刻只能有一個執行執行緒

Linux程序通訊--共享記憶體與訊號量

1. 建立共享記憶體,shmget() shmget(建立或開啟共享記憶體) 表頭檔案#include <sys/ipc.h>#include <sys/shm.h> 函式定義  int shmget(key_t key, size_t size, int shmflg); 函式說明k

Qt程序通訊——共享記憶體

       Qt提供了一種安全的共享記憶體的實現QSharedMemory,以便在多執行緒和多程序程式設計中安全的使用。比如說QQ的聊天的客戶端,這裡有個個性頭象,當點選QQ音樂播放器的時候,QQ

Linux環境程序通訊——共享記憶體

原文連結     原文連結:http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html 概述     Android系統中大量使用了mmap實現的共享記憶體,所以這裡需要介紹一下LInux程序間通訊

Linux IPC——簡單應用 共享記憶體Share Memory

目錄   一:共享記憶體 1.1定義 1.2優缺點 1.2.1 優點 1.2.2缺點 1.3共享記憶體結構維護 1.4共享記憶體的通訊原理 二:相關函式介面 2.1 Linux命令 2.1.1檢視系統中的共享儲存段  2.1.2

【轉】程序通訊的方式8種

程序間通訊的方式——訊號、管道、訊息佇列、共享記憶體 多程序: 首先,先來講一下fork之後,發生了什麼事情。 由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序

程序通訊第二章Posix IPC

1.概述 Posix IPC的三種類型: Posix訊息佇列 Posix訊號量 Posix共享記憶體區 2.IPC名字 三種類型的Posix IPC都使用“Posix IPC名字“進行標識。 Posix IPC名字的移植性問題採用:px_ipc_name函式。

程序通訊方式總結適用初學者

前言:linux的程序間通訊概述 1、為什麼需要程序間通訊       (1)程序間通訊(IPC)指的是2個任意程序之間的通訊。       (2)同一個程序在一個地址空間中,所以同一個程序的不同模組(不同函式、不同檔案)之間都是很簡單的(很多時候都是全域性變數、也可以通

Linux 程序通訊之:記憶體共享Shared Memory

一、簡介 共享記憶體允許兩個程序訪問同一塊記憶體區域,它們使用同一個 key 值標記。 二、特點 優點: 通訊方便,兩個程序也是直接訪問同一塊記憶體區域,減少了資料複製的操作,速度上也有明顯優勢。 缺點: 沒有提供同步機制,往往需要我們使用其它(例如訊號)等手段實

程序通訊共享記憶體程式碼實現

共享記憶體:1.共享記憶體就是允許兩個不相關的程序訪問同一個邏輯記憶體;                     2.共享記憶體是在兩個正在執行的程序之間共享和傳遞資料的一種最有效的方式;                     3.不同程序之間共享的記憶體通常安排為同一段

Boost.Interprocess使用手冊翻譯之四:在程序共享記憶體 Sharing memory between processes

共享記憶體 共享記憶體是最快速的程序間通訊機制。作業系統在幾個程序的地址空間上對映一段記憶體,然後這幾個程序可以在不需要呼叫作業系統函式的情況下在那段記憶體上進行讀/寫操作。但是,在程序讀寫共享記憶體時,我們需要一些同步機制。 考慮一下服務端程序使用網路機制在同一臺

C# .Net 多程序同步 通訊 共享記憶體 記憶體對映檔案 Memory Mapped

節點通訊存在兩種模型:共享記憶體(Shared memory)和訊息傳遞(Messages passing)。         記憶體對映檔案對於託管世界的開發人員來說似乎很陌生,但它確實已經是很遠古的技術了,而且在作業系統中地位相當。實際上,任何想要共享資料的通訊模型都