轉自於 http://blog.csdn.net/xiaoweibeibei/article/details/6552498
引用標識符:引用標識符是一個整數,表示每一個SYSV子系統的對象(共用記憶體,訊號量,訊息佇列),它用於訪問對象是在系統中的傳遞。
鍵:在SYSV子系統中用於定位系統中的應用標識符,它相當於一種路由演算法,用來決定如何訪問一個SYSV子系統的對象。
ipc_perm結構:它對應於每一個進程通訊機制的對象,其定義如下:
struct ipc_perm{
uid_t uid;// 所有者的有效使用者ID
gid_t gid;//所有者的有效使用者組ID
uid_t cuid;//建立者的有效使用者ID
gid_t cgid;//建立者的有效使用者組ID
mode_t mode;//表示此對象的存取權限
ulong seq;//對象的應用序號
key_t key;//對象的鍵
}
說明:
(1)mode:與檔案存取權限不同的是,對於共用記憶體和訊息佇列的存取權限包括“可讀”和“可寫”,訊號量的存取權限包括“可讀”和“可改變”。
(2)可以使用ipcs命令查看處理序間通訊機制中對象的狀態,該命令的參數有-m, -s和-q,分別表示查看共用記憶體,訊號量和訊息佇列。使用預設參數時這三種狀態都輸出。
共用記憶體
共用記憶體通訊是Linux系統中最底層的通訊機制,也是最快速的通訊機制,通過兩個或多個進程共用同一塊記憶體地區來實現進程間的通訊。使用共用記憶體進行處理序間通訊時最重要的問題是如果解決進程的同步問題。使用共用記憶體的方法有兩種,即:映射/dev/mem裝置和記憶體映像。
shmid_ds結構:
struct shmid_ds{
struct ipc_perm shm_perm;//對應於該共用記憶體的ipc_perm結構;
int shm_segsz;//以位元組表示共用記憶體的大小;
ushort shm_lkcnt;//共用記憶體地區被鎖定的時間數;
pid_t shm_cpid;//建立該共用記憶體的進程ID;
pid_t shm_lpid;//最忌一次調用shmop函數的進程ID;
ulong shm_nattch;//當前使用該共用記憶體地區的進程數;
time_t shm_atime;//最近一次附加操作的時間;
time_t shm_dtime;//最近一次分離操作的時間;
time_t shm_ctime;//最近一次改變的時間;
}
共用記憶體的建立與開啟
函數:int shmget(key_t key,int size, int falg);
標頭檔:sys/types.h sys/ipc.h sys/shm.h
函數作用:用於建立一個新的共用記憶體或開啟一個已經存在的共用記憶體;
函數說明:
key:表示所建立或開啟的共用記憶體的鍵;
size:表示共用記憶體地區的大小,只在建立一個新的共用記憶體時有效;
flag:表示調用函數的操作類型,也用於表示共用記憶體的存取權限,兩隻通過邏輯或表示。
調用函數的作用由key和flag決定:具體如下:
key為IPC_PRIVATE:表示建立一個新共用記憶體,flag取值無效;
key不為IPC_PRIVATE,flag為IPC_CREATE 而沒有設定IPC_EXCEL位:操作由key決定,如果key是已經存在,則為開啟操作,不存在為建立操作;
key不為IPC_PRIVATE,flag而沒有IPC_CREATE和IPC_EXCEL位:只執行建立共用記憶體操作,且參數key值不能與核心中已經存在的任何共用記憶體的索引值相同,否則調用失敗;
函數調用成功,返回為共用記憶體的引用標識符,調用失敗時,傳回值為-1。
附加
函數:void* shmat(int shmid,void *addr,int flag);
標頭檔:sys/types.h sys/ipc.h sys/shm.h
函數說明:
shmid表示要附加的共用記憶體的引用標識符;flag表示shmat函數的操作方式。其中參數addr和flag共同決定共用記憶體地區要附加到的地址值,一般為0。
Addr為0,系統自動尋找進程地址空間,將共用記憶體地區附加到第一塊有效記憶體地區上,flag此時無效;
addr不為0,而flag沒有設定SHM_RND位,則,共用記憶體地區附加到由addr指定的地址處;
addr不為0,而flag設定了SHM_RND位,則共用記憶體地區附加到有addr(addr mod SHMLBA)計算得到的地址處;
SHM_RND意為取整,SHMLAB意為低邊界地址的倍數,它總是2的乘方,該算式是將地址向下取最近一個SHMLAB的倍數,一般而言不需要設定SHM_RND,如果需要以唯讀方式串連恭喜那個段,需要設定flag為SHM_RDONLY位。
Shmat函數傳回值是該段所串連的實際地址值,如果出錯返回(void *)-1,調用成功為共用記憶體地區的指標。
分離
函數:int shmdt(void *addr);
標頭檔:sys/types.h sys/ipc.h sys/shm.h
函數說明:
shmdt的調用可以使共用記憶體與該進程的地址分離,但不刪除恭喜那個記憶體本身,addr為要分離共用記憶體區的指標,也就是調用shmat函數的傳回值,調用成功時返回0,失敗返回-1;
共用記憶體的控制
函數:int shmctl( int shmid,int cmd,struct shmid_ds *buf);
標頭檔:sys/types.h sys/ipc.h sys/shm.h
函數說明:
參數shmid為共用記憶體的引用標識符。參數cmd表示調用該函數希望執行的操作,其取值如下:
SHM_L0CK:將共用記憶體地區上鎖,只能由超級使用者執行;
IPC_RMID:用於刪除 共用記憶體。執行該命令後,共用記憶體的應用標識符將立即被刪除,該共用記憶體不能再被其它進程所附加。但是改共用記憶體的真正刪除要等所有已經附加到該共用記憶體的結束或斷開與該共用記憶體的串連後才執行;
IPC_SET:按參數buf指向的結構中的值設定該共用記憶體對應的shmid_ds結構,只有有效使用者ID和共用記憶體的所有者或建立者ID相同的使用者進程,以及超級使用者進程才能執行這一操作;
IPC_STAT:用於取得該恭喜那個記憶體的shmid_ds結構,儲存於buf指向的緩衝區;
SHM_UNLOCK:將上鎖的共用記憶體區釋放,只能由超級使用者執行。
訊號量機制
訊號量是一種用於對多個進程訪問共用資料進行控制的一種機制,主要是為瞭解決互斥共用資源的同步問題的一種機制。當有進程要訪問某一資源時候,首先檢查該資源的訊號量,如果大於1,則可以使用,同時使訊號量減1,當訪問結束後,訊號量在加1,當訊號量為0時,進程休眠,直到訊號量的值大於0時,進程被喚醒。
雙態訊號量:初始值為1,任意時刻最多隻有一個進程可以訪問。
不能定義一個訊號量,只能定義一個訊號量集,同一訊號量集只能使用同一引用ID,每一個訊號量集都只有一個與其對應的結構,該結構定義如下:
struct semid_ds{
struct ipc_perm sem_perm;//訊號量集的ipc_perm結構
struct sem *sem_base;//指向訊號量集的第一個訊號量的sem結構
ushort sem_nsems;//訊號量集中訊號的個數
time_t sem_otime;//最近一次調用semop的時間
time_t sem_ctime;//最近一次改變該訊號量集的時間
}
sem結構記錄了一個訊號量的資訊,其定義如下:
struct sem{
ushort semval;//訊號量的值
pid_t sempid;//最近一次訪問資源的的進程ID
ushort semncnt;//等待可利用資源出現的進程數
ushort semzcnt;//等待全部資源可被獨佔的進程數
}
訊號量集的建立與開啟
函數:int semget(key_t key,int nsems,int flag);
標頭檔: sys/types.h sys/ipc.h sys/shm.h
函數說明:
該函數用於建立或開啟一個已經存在的訊號量集,其參數和shmget功能類似。當該函數調用成功時,返回訊號量集的引用標識符,調用失敗返回-1;當調用該函數建立一個訊號量時,其相應的semid_ds被初始化。
訊號量的操作
函數:int semop(int semid,struct sembuf semoparray[],size_t nops);
標頭檔:sys/types.h sys/ipc.h sys/shm.h
函數說明:
semid為訊號量集的引用ID;semoparray指定調用semop的操作,nops指定semoparray的元素個數。semoparray的每個元素表示一個操作,該函數是一個原子操作,一旦執行就將執行數組中的所有操作
struct sembuf結構
struct sembuf{
ushort sem_num;//指定要操作的訊號量
short sem_op;//所要執行的操作
short sem_flag;//操作標記,取值有IPC_NOWAIT和SEM_UNDO
}
sem_op說明:
sem_op>0:表示該資源使用完畢,交回該資源。此時訊號量集的semid_ds結構的sem_base.semval將加上sem_op的絕對值。若此時設定了SEM_UNDO位,該訊號量的調整值將減去sem_op的值;
sem_op=0:表示進程要等待,直至sem_base.semval表為0;
sem_op<0:表示進程希望使用該資源。此時將比較sem_base.semval和sem_op的絕對值的大小。如果sem_base.semval大於sem_op的絕對值,說明資源足夠分配給此進程,則sem_base.semval將減去sem_op的絕對值。若此時設定了SEM_UNDO位,則訊號量的調整值將加上sem_op的絕對值。如果sem_base.semval小於sem_op的絕對值,表示資源不足。若設定了IPC_NOWAIT位,則函數出錯返回,否則semid結構中的sem_base.semncnt加1,進程等待直至sem_base.semval大於等於sem_op的絕對值或該訊號量被刪除。
訊號量的控制
函數: int semctl(int semid, int semnum,int cmd,union semun arg);
標頭檔:sys/types.h sys/ipc.h sys/shm.h
函數說明:semid是要引用訊號量集的引用標識符,semmum用於指明某個特定訊號量,cmd為要執行的操作。
union semun結構
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo * __buf;//linux特有
}
說明:
該聯合體中各個變數的使用方式與參數cmd有關,具體如下:
GETALL:擷取semid所表示的訊號量集中訊號量的數量,並將該值存放在無符號短整數arg.array中;
GETNCNT:擷取semid所表示的訊號量集中等待給定訊號量鎖定進程數目,即semid_ds結構中sem.semncnt的值;
GETPID:擷取semid所表示的訊號量集中最後一個使用semop函數的進程ID,即semid_ds結構中sem.sempid的值;
GETVAL:擷取semid所表示的訊號量集中semnum所指定訊號量的值;
GETZCNT:擷取semid所表示的訊號量集中等待訊號量為0的進程數目,即semid_ds結構中sem.semncnt的值;
IPC_RMID:刪除該訊號量;
IPC_SET:按參數arg.buf指向的結構體中的值設定該型號量對應的semid_ds結構。只有有效使用者ID和訊號量的所有者ID或建立者ID相同的使用者進程,以及超級使用者進程可以執行這一操作;
IPC_STAT:擷取該訊號量的semid_ds結構,儲存在arg.buf指向的緩衝區中;
SETALL:以arg.array中的值設定semid所表示的訊號量集中訊號量的個數;
SETVAL:設定semid所表示的訊號量集中semnum所指定訊號量的值;
管道
當管道建立後,產生兩個檔案描述符,一個用於讀取,一個用於寫入,他只能用於兩個進程之間的通訊,且這兩個進程必須有同一個進程所派生,即:這兩個進程必須是同源進程。管道的通訊是半雙工的,只允許單方向的傳輸資料。由於管道類似於檔案操作,因此,當管道建立後,就可以採用檔案操作的方式來對管道進行讀取。管道不是一個真實存在的檔案,他只在核心中儲存,不存在於檔案系統中。在管道的讀寫工程中,要注意分清是資料轉送暫時無資料讀取還是資料轉送結束。
管道的建立
函數:int pipe(int filedescriptors[2]);
標頭檔:unistd.h
函數數名:filedescriptors[0]表示讀取端檔案描述符,filedescryipto-
rs[1]用於寫入端檔案描述符,調用成功返回0,失敗返回-1。當調用哪個pipe建立一個通道後 ,進程只能將檔案描述符傳遞給子進程方才可以實現通訊,較為常用的做法是調用exec函數使子進程執行所需程式,然後根據資料轉送方向關閉父進程和子進程的檔案描述符。
具名管道
命令管道又叫先進先出管道,其存在於檔案系統中,是一種特殊的管道,其特點有:
l 可以用於任何兩個進程之間通訊;
l 由於具名管道存在於檔案系統中,當進程對具名管道使用結束後,其依然存在於檔案系統中,除非對其進行了刪除操作;
l 具名管道仍只能用於單向資料轉送,如果用具名管道實現兩個處理序間通訊資料區段相互交換,需要使用兩條具名管道。
具名管道的建立
函數: (1) int mkefifo(const char *pathname,mode_t mode);
(2) int mknod(char *pathname,mode_t mode,dev_t dev);
標頭檔:sys/types.h sys/stat.h
函數說明:pathname用於存放具名管道的檔案名稱,mode用於指定所建立檔案的許可權,調用成功返回0,失敗返回-1;mknod不是專用於建立管道的函數,當dev為0 時,表示建立一個具名管道;
建立命令管道的shell命令: mkfifo FIFO_TEST mknod FIFO+TEST p
具名管道使用注意事項:
l 建立具名管道後,它只存在於檔案系統,如果要使用,需要在進程中開啟,如果沒有進程寫開啟一個具名管道,就對其進行寫操作,將產生SIGPIPE訊號,write函數將errno設定為出錯號;
l 系統定義的常數PIPE_BUF規定了具名管道緩衝的大小,當寫入資料超過規定大小時,將會使資料發生交錯;
l 當一個進程從具名管道中讀取資料時,如果具名管道中的全部資料讀寫完了,則read函數認為讀到檔案末尾,傳回值為0,但又可能資料區段寫入並沒結束,寫入具名管道的進程還有資料要傳輸。一次,要分清是資料轉送結束還是暫時無資料讀取,如果是後者,則必須讓讀取資料的進程等待。
技巧:
使用具名管道時,需要在兩個將進行通訊的進程中分別開啟具名管道,因此,當一個讀開啟(或寫開)一個具名管道而沒有其他進程寫開啟(或讀開啟)此具名管道時,該進程就會進入阻塞狀態,直到另外一個進程寫開啟(或讀開啟)此具名管道。
刪除具名管道函數:int unlink(const char* pathname);
標頭檔: unistd.h
訊息佇列
訊息佇列是一系列連續排列的訊息,儲存在核心中,通過訊息佇列的引用標識符來訪問。其與管道有些相似,但其優點是每個訊息指定訊息類型,接受訊息的進程可以請求介紹下一條訊息,也可以請求接受下一條特定的訊息。
訊息佇列有兩部分組成,即:訊息類型和所傳遞的資料。一般用結構來表示。
msgid_ds結構:
struct msgid_ds{
struct ipc_perm msg_perm;//對應於訊息佇列的ipc_perm結構指標;
struct msg *msg_first;//指向訊息佇列中的第一個訊息;
struct msg *msg_last;//指向訊息佇列中的最後個訊息;
ulong msg_types;//記錄訊息佇列中當前的總位元組數;
ulong msg_gnum;//記錄訊息佇列中當前的總訊息數;
ulong msg_qbytes;//記錄訊息佇列中最大可容納的位元組數;
pid_t msg_lspid;//最近一次執行msgsnd函數的進程的ID;
pid_t msg_lrpid;//最近一次執行msgrcv函數的進程的ID;
time_t msg_stime;//最近一次執行msgsnd函數的時間;
time_t msg_rtime;//最近一次執行msgrcv函數的時間;
time_t msg_ctime;//最近一次改變該訊息佇列的時間;
}
訊息佇列的建立與開啟
函數: int msgget(key_t key, int flag);
標頭檔: sys/types.h sys/ipc.h sys/msg.h
函數說明:和共用記憶體的建立相似;
訊息的發送
函數: int msgsnd( int msgid, const void *ptr, size_t nbytes, int flag);
標頭檔:sys/types.h sys/ipc.h sys/msg.h sys/msg.h
函數說明:該訊息將添加訊息到隊尾,msgid為訊息佇列引用標識符,ptr是指向要發送的訊息的指標,nbytes記錄發送訊息中資料的長度,flag為指定訊息佇列滿時的處理方法。如果設定了IPC_NOWAIT位,則立即出錯返回,否則發送訊息的進程被阻塞,直至訊息佇列中有空間或該訊息佇列被刪除時候返回。調用成功時,返回0;失敗時,返回-1。
訊息的接收
函數:int msgrcv( int msgid,void *ptr,size_t nbytes,long types,int flag);
標頭檔:sys/types.h sys/ipc.h sys/msg.h
函數說明:ptr為接受訊息的緩衝區,當函數調用成功時,傳回值為接收到訊息的長度,以位元組計,失敗時返回-1。
type含義如下:
type 取值 |
含義 |
0 |
接收隊列第一條訊息 |
>0 |
接收隊列中類型值等於type的第一條訊息 |
<0 |
接收隊列中類型值小於等於type絕對值中,類型值最小的訊息中第一條訊息 |
flag取值:
IPC_NOWAIT:指定type位無效時的處理方法,如果被設定,,則立即出錯返回,否則接收訊息的進程被阻塞,直至type位有效或該訊息佇列被刪除。
MSG_NOERROR:用於設定訊息長度大於nbytes時的方法,如果該位被設定,當訊息長度大於nbytes時,超出部分被截斷,否則,不接收該訊息,將其保留在訊息佇列中,出錯返回。
訊息佇列的控制
函數: int msgctl(int msgid,int cmd,struct msgid_ds *buf);
標頭檔:sys/types.h sys/ipc.h sys/msg.h
函數說明:msgid為訊息佇列的引用標識符,其中cmd取值如下:
IPC_RMID:刪除訊息佇列。如果有進程對此訊息佇列進行操作,則出錯返回。只有有效使用者ID,訊息佇列所有者ID或與建立者ID相同的用於進程,已經超級管理使用者進程可以執行該操作;
IPC_SET:按參數buf指向的結構中的值設定該訊息佇列對應的msgid_ds結構。只有有效使用者ID,訊息佇列所有者ID或與建立者ID相同的用於進程,已經超級管理使用者進程可以執行該操作;
IPC_STAT:擷取該訊息佇列的msgid_ds結構,儲存於buf所指向的緩衝區。