進程通訊之共享內存

共享內存
共享內存就是贊成兩個不相關的進程訪問同一個邏輯內存。共享內存是在兩個正在執行的進程之間共享和傳遞數據的一種頗有效的方式。不一樣進程之間共享的內存一般安排爲同一段物理內存。

進程可以將同一段共享內存鏈接到它們本身的地址空間中,所有進程都可以訪問共享內存中的地址。就好像它們是由用C語言函數malloc分配的內存同樣。html

而假設某個進程向共享內存寫入數據,所作的修改將立刻影響到可以訪問同一段共享內存的不論什麼其它進程。數據結構


共享內存並未提供同步機制,也就是說。在第一個進程結束對共享內存的寫操做以前,並沒有本身主動機制可以阻止第二個進程開始對它進行讀取。函數

因此咱們一般需要用其它的機制來同步對共享內存的訪問。ui

http://blog.csdn.net/xiaoliangsky/article/details/40024657spa

共享內存相關的函數操作系統

1建立共享內存shmget.net

函數原型:int   shmget(key_t   key,   size_t   size,   int  shmflag);
code

key: 標識符的規則
size:共享存儲段的字節數
shmflag:讀寫的權限
返回值:成功返回共享存儲的id,失敗返回-1
-----------------------------------------------
key 標識共享內存的鍵值:0/IPC_PRIVATE。當key的取值爲IPC_PRIVATE建立一塊新的內存;假設key的取值爲0。而參數shmflg中設置了IPC_PRIVATE這個標誌,則相同將建立一塊新的共享內存。
htm


在IPC的通訊模式下,不管是使用消息隊列仍是共享內存。甚至是信號量,每個IPC的對象(object)都有惟一的名字。稱爲「鍵」(key)。對象

經過「鍵」。進程能夠識別所用的對象。「鍵」與IPC對象的關係就如同文件名稱稱之於文件,經過文件名稱。進程能夠讀寫文件內的數據,甚至多個進程能夠共用一個文件。而在IPC的通信模式下。經過「鍵」的使用也使得一個IPC對象能爲多個進程所共用。
Linux系統中的所有表示System V中IPC對象的數據結構都包括一個ipc_perm結構。當中包括有IPC對象的鍵值。該鍵用於查找System V中IPC對象的引用標識符。

假設不使用「鍵」,進程將沒法存取IPC對象,因爲IPC對象並不存在於進程自己使用的內存中。


一般,都但願本身的程序能和其它的程序預先約定一個惟一的鍵值,但實際上並不是總可能的成行的。因爲本身的程序沒法爲一塊共享內存選擇一個鍵值。所以,在此把key設爲IPC_PRIVATE。這樣。操做系統將忽略鍵,創建一個新的共享內存,指定一個鍵值。而後返回這塊共享內存IPC標識符ID。

而將這個新的共享內存的標識符ID告訴其它進程可以在創建共享內存後經過派生子進程,或寫入文件或管道來實現。



int size(單位字節Byte)
-----------------------------------------------
    size是要創建共享內存的長度。所有的內存分配操做都是以頁爲單位的。因此假設一段進程僅僅申請一塊僅僅有一個字節的內存,內存也會分配整整一頁(在i386機器中一頁的缺省大小PACE_SIZE=4096字節)這樣,新建立的共享內存的大小其實是從size這個參數調整而來的頁面大小。即假設size爲1至4096,則實際申請到的共享內存大小爲4K(一頁);4097到8192,則實際申請到的共享內存大小爲8K(兩頁),依此類推。

int shmflg
-----------------------------------------------
    shmflg主要和一些標誌有關。

當中有效的包含IPC_CREAT和IPC_EXCL,它們的功能與open()的O_CREAT和O_EXCL至關。
    IPC_CREAT   假設共享內存不存在,則建立一個共享內存,不然打開操做。
    IPC_EXCL    僅僅有在共享內存不存在的時候,新的共享內存才創建,不然就產生錯誤。



    假設單獨使用IPC_CREAT,shmget()函數要麼返回一個已經存在的共享內存的操做符,要麼返回一個新建的共享內存的標識符。假設將IPC_CREAT和IPC_EXCL標誌一塊兒使用,shmget()將返回一個新建的共享內存的標識符。假設該共享內存已存在,或者返回-1。IPC_EXEL標誌自己並無太大的意義,但是和IPC_CREAT標誌一塊兒使用可以用來保證所得的對象是新建的。而不是打開已有的對象。對於用戶的讀取和寫入許可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一組讀取和寫入許可。而(SHM_R>6)和(SHM_W>6)是全局讀取和寫入許可。

返回值
-----------------------------------------------
成功返回共享內存的標識符。不成功返回-1,errno儲存錯誤緣由。
    EINVAL        參數size小於SHMMIN或大於SHMMAX。


    EEXIST        預創建key所致的共享內存,但已經存在。
    EIDRM         參數key所致的共享內存已經刪除。
    ENOSPC        超過了系統贊成創建的共享內存的最大值(SHMALL )。
    ENOENT        參數key所指的共享內存不存在,參數shmflg也未設IPC_CREAT位。
    EACCES        沒有權限。


    ENOMEM        核心內存不足。


2 鏈接共享內存shmat

函數原型:void* shmat(int shmid, const void *shmaddr, int shmflag)

鏈接共享內存標識符爲shmid的共享內存,鏈接成功後把共享內存區對象映射到調用
進程的地址空間。隨後可以像在本地空間同樣訪問。

-----------------------------------------------

shmid 共享內存標識符。由shmget函數返回的id
shmaddr 指點共享內存出現在進程內存地址的什麼位置,直接指定爲NULL時。有內核本身決定
一個合適的地址位置。
shmflg SHM_RDONLY:爲僅僅讀模式,其它爲讀寫模式

返回值

-----------------------------------------------

成功:附件好的共享內存地址
出錯:-1。錯誤緣由存在於error中
注意:fork後子進程繼承已鏈接的共享內存地址。

exec後該子進程與共享的內存地址本身主動脫離。
進程結束後。已鏈接的共享內存地址會本身主動脫離。

錯誤代碼

-----------------------------------------------

EACCES:無權限已指定方式鏈接共享內存
EINVAL:    無效的參數shmid或shmaddr
ENOEME:核心內存不足


3「分離」共享內存shmdt

函數原型:int shmdt(const void *shmaddr)

用來斷開與共享內存附加點的地址空間。阻止本進程訪問此片共享內存。


shmaddr:鏈接的共享內存的起始地址

返回值

-----------------------------------------------

成功返回0
出錯返回-1。錯誤緣由存在於error中
注意:本函數調用並不刪除所指定的共享內存區。而僅僅是將先前用shmat函數鏈接(attach)好的共享內存脫離(detach)眼下的進程

錯誤碼

-----------------------------------------------

EINVAL:無效的參數shmaddr


4管理共享內存shmctl

函數原型:int  shmctl(int   shmid,    int   cmd,    struct   shmid_ds   *buf)

管理共享沒存。

-----------------------------------------------

shmid 共享內存標識符
cmd     IPC_STAT:獲得共享內存的狀態,把共享內存的shmid_ds結構拷貝到buf;
            IPC_SET:改變共享內存的狀態,把shmid_ds中的uid、gid、mode拷貝到共享內存的shmid_ds結構體。
            IPC_RMID:刪除這片共享內存
buf 共享內存管理結構體。詳細說明參見貢獻內存內核結構定義部分。

返回值

-----------------------------------------------

成功返回0
出錯返回-1,錯誤緣由存在於error中

錯誤代碼

-----------------------------------------------

EACCESS:參數cmd爲IPC_STAT,確無權限讀取該共享內存
EFAULT:參數buf指向無效的內存地址
EIDRM:標識符爲msqid的共享內存已被刪除

EINVAL:無效的參數cmd或shmid
EPERM:參數cmd爲IPC_SET或IPC_RMID,卻無足夠的權限運行


最後來一個樣例:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <error.h>

#define MEMORY_SIZE 1024

int main()
{
	int               wpid;
	int               status;
	int               failed;
	int               shmid;
	char             *addr;
	pid_t             pid;
	struct shmid_ds   buf;

	failed = 0;

	shmid  = shmget(IPC_PRIVATE, MEMORY_SIZE, IPC_CREAT|0600);
	if (shmid == -1)
	{
		perror("shmget error");
		return -1;
	}

	pid = fork();
	if (pid == 0)
	{
		addr = (char*)shmat(shmid, NULL, 0);
		if ((int)addr == -1)
		{
			perror("shmat addr error");
			return -1;
		}

		strcpy(addr, "I am the child process\n");

		shmdt(addr);
		
		return 3;
	}
	else if (pid > 0)
	{
		wpid = waitpid(pid, &status, 0);
		if (wpid > 0 && WIFEXITED(status))
		{
			printf("child process return is %d\n", WEXITSTATUS(status));
		}

		failed = shmctl(shmid, IPC_STAT, &buf);
		if (failed == -1)
		{
			perror("chmctl error");
			return -1;
		}
		
		printf("shm_segsz =%d bytes\n", buf.shm_segsz);
        printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid);
        printf("chlid pid=%d, shm_lpid = %d \n", pid, buf.shm_lpid);
		printf("mode = %08x \n", buf.shm_perm.mode);

		addr = (char*)shmat(shmid, NULL, 0);
		if ((int)addr == -1)
		{
			perror("shmat addr error");
			return -1;
		}
	
		printf("%s", addr);
		shmdt(addr);
		shmctl(shmid, IPC_RMID, NULL);
	}	
	else 
	{
		perror("fork error");
		shmctl(shmid, IPC_RMID, NULL);
		return -1;
	}

	return 0;
}


未完

待續;

參考:

http://blog.csdn.net/guoping16/article/details/6584058

相關文章
相關標籤/搜索