shm*()--共享記憶體操作函式
要使用共享記憶體,應該有如下步驟:
1.開闢一塊共享記憶體 shmget()
2.允許本程序使用共某塊共享記憶體 shmat()
3.寫入/讀出
4.禁止本程序使用這塊共享記憶體 shmdt()
5.刪除這塊共享記憶體 shmctl()或者命令列下ipcrm
系統建立IPC通訊(如訊息佇列、共享記憶體時)必須指定一個ID值。通常情況下,該id值通過ftok函式得到。
ftok原型如下:
key_t ftok( char * fname, int id )
fname就時你指定的檔名(該檔案必須是存在而且可以訪問的),id是子序號,雖然為int,但是隻有8個位元被使用(0-255)。
當成功執行的時候,一個key_t值將會被返回,否則 -1 被返回。
shmkey = ftok( "mcut" , 'a' ); // 計算識別符號
#include <sys/ipc.h>
#include <sys/shm.h>
int
shmget(key_t key, size_t size, int shmflg);
key_t key
-----------------------------------------------
key標識共享記憶體的鍵值: 0/IPC_PRIVATE。 當key的取值為IPC_PRIVATE,則函式shmget()將建立一塊新的共享記憶體;如果key的取值為0,而引數shmflg中設定了IPC_PRIVATE這個標誌,則同樣將建立一塊新的共享記憶體。
在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
返回值
-----------------------------------------------
成功返回共享記憶體的識別符號;不成功返回-1,errno儲存錯誤原因。
EINVAL 引數size小於SHMMIN或大於SHMMAX。
EEXIST 預建立key所致的共享記憶體,但已經存在。
EIDRM 引數key所致的共享記憶體已經刪除。
ENOSPC 超過了系統允許建立的共享記憶體的最大值(SHMALL )。
ENOENT 引數key所指的共享記憶體不存在,引數shmflg也未設IPC_CREAT位。
EACCES 沒有許可權。
ENOMEM 核心記憶體不足。
struct shmid_ds
-----------------------------------------------
shmid_ds資料結構表示每個新建的共享記憶體。當shmget()建立了一塊新的共享記憶體後,返回一個可以用於引用該共享記憶體的shmid_ds資料結構的識別符號。
include/linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
struct ipc_perm
-----------------------------------------------
對於每個IPC物件,系統共用一個struct ipc_perm的資料結構來存放許可權資訊,以確定一個ipc操作是否可以訪問該IPC物件。
struct ipc_perm {
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};