進程間通信
數據傳輸:一個進程需要將它的數據發送給另一個進程
資源共享:多個進程間共享同樣的資源
通知事件
進程控制
POXIX:可移植操作系統接口
LINUX使用的進程間通信方式包括:
1、 管道(pipe)和有名管道(FIFO)
2、 信號(sigal)
3、 消息隊列
4、 共享內存
5、 信號量
6、 套接字(socket)
一、管道通信
特點:管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關係的進程間使用。進程的親緣關係通常是指父子進程關係。
1、管道是單向的,先進先出的
2、管道包括無名管道和有名管道,前者用於父進程和子進程間的通信,後者可用於同一系統中的任意兩個進程間的通信
無名管道由pipe()函數創建 intpipe(int filedis [2]);
3、當一個管道建立時,它會創建兩個文件描述符:filedis[0]用於讀管道,filedis[1]用於寫管道
4、管道關閉用close逐個關閉
5、管道讀寫
6、管道用於不同進程間通信,通常先創建一個管道,再通過fork函數創建一個子進程,該子進程會繼承父進程所創建的管道
注意:必須在系統調用fork()前調用pipe(),否則子進程將不會繼承文件描述符
7、命名管道(FIFO)
不想關的進程也能交換數據
創建:int mkfifo(const char*pathname,mode_t mode)
Pathname:FIFO文件名
Mode:屬性
一旦創建了一個FIFO,就可以用open打開它,一般的文件訪問函數(close、read、write等)都可用於FIFO操作。當打開FIFO時,非阻塞標誌(O_NONBLOCK)將對以後的讀寫產生如下影響:
(1) 沒有使用O_NONBLOCK:訪問要求無法滿足時進程將阻塞。如試圖讀取空的FIFO,將導致進程阻塞
(2) 使用O_NONBLOCK:訪問要求無法滿足時不阻塞,立刻出錯返回,errno是ENXIO
二、信號通信
特點: 信號是一種比較複雜的通信方式,用於通知接收進程某個事件已經發生。
1、 幾種常見的信號
SIGHUP:從終端上發出的結束信號
SIGINT:來自鍵盤的中斷信號(Ctrl+C)
SIGKILL:該信號結束接受信號的進程
SIGTERM:kill命令發出的信號
SIGCHLD:標識子進程停止或結束的信號
SIGSTOP:來自鍵盤(Ctrl+Z)或調試程序的停止執行信號
2、 信號處理
(1) 忽略此信號(有兩種信號不能被忽略,SIGKILL和SIGSTOP)
(2) 執行用戶希望的動作:通知內核在某種信號發生時,調用一個用戶函數,在用戶函數中執行用戶希望的處理
(3) 執行系統默認動作:對大多數的系統默認動作是終止該進程
3、 信號發送
發送信號的主要函數有kill和raise
區別:kill既可以自身發送信號,也可以向其他進程發送信號,raise函數向進程自身發送信號
int kill(pid_t pid,int signo);
int raise(int signo);
kill的pid參數有四種不同的情況:
(1) pid>0:將信號發生給進程ID爲pid的進程
(2) pid==0:將信號發送給同組的進程
(3) pid<0:將進程發送給其進程組ID等於pid絕對值的進程
(4) pid==-1:將信號發送給所有進程
Alarm:使用alarm函數可以設置一個時間值(鬧鐘時間),當所設置的時間到了時,產生SIGALRM信號,如果不捕捉此信號,則默認動作是終止該進程
Unsigned Int alarm(unsigned int seconds);
經過了指定seconds秒後會產生信號SIGALAM
Pause:Pause函數使調用進程掛起直至捕獲到一個信號:int pause(void);
只有執行了一個信號處理函數後,掛起才結束
Signal函數:
Void (*signal(int signo,void(*func)(int)))(int)
Func可能的值是:
(1) SIG_IGN:忽略此信號
(2) SIG_DFL:按系統默認方式處理
(3) 信號處理函數名:使用該函數處理
三、共享內存
特點:共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的IPC方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號量,配合使用,來實現進程間的同步和通信
共享內存分爲兩個步驟
1、 創建共享內存,使用shmget函數
2、 映射共享內存, 這段創建的共享內存映射到具體的進程空間去,使用shmat函數
Int shmget(key_t key,int size,int shmflg);
Int shmat(int shmid,char *shmaddr,int flag);
當一個進程不再需要共享內存時,需要把它從進程地址空間中脫離
Int shmdt(char*shmaddr);
四、消息隊列
特點:消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點
消息隊列就是一個消息的鏈表
消息隊列的內核持續性要求每個消息隊列都在系統範圍內對應唯一的鍵值,所以,要獲得一個消息隊列的描述字,必須提供該消息隊列的鍵值
Key_t ftok(char *pathname,char proj)
功能:返回文件名對應的鍵值
Pathname:文件名
Proj:項目名(不爲0即可)
獲取消息隊列的描述字:
Int msgget(key_t key,int msgflg)
Key:鍵值,由ftok獲得
Msgflg:標誌位
返回值:與鍵值key相對應的消息隊列描述字
標誌位:IPC_CREAT 創建新的消息隊列,IPC_EXCL與IPC_CREAT一同使用,表示如果要創建的消息隊列已經存在,則返回錯誤,IPC_NOWAIT讀寫消息隊列要求無法得到滿足時,不阻塞
在以下兩種情況下,將創建一個新的消息隊列:
(1)如果沒有與鍵值key相對應的消息隊列,並且msgflg中包含了IPC_CREAT標誌位(2)key參數爲IPC_PRIVATE
Int msgsnd(int msgid,struct msgbuf*msgp,int msgsz,int msgflg);
功能:向消息隊列中發送一條消息
Msqid:已打開的消息隊列id
Msgp:存放消息的結構
Msgsz:消息數據長度
Msgflg:發送標誌,有意義的msgflg標誌爲NOWAIT,指明在消息隊列沒有足夠空間容納要發送的消息時,msgsnd是否等待
消息格式:struct msgbuf
{
Long mtype;//消息類型>0
Char mtext[1];//消息數據的首地址
}
接收消息:
Int msgrcv(int msqid,structmysbuf *msgp,int msgsz,long msgtyp,int msgflg)
功能:從msqid代表的消息隊列中讀取一個msgtyp類型的消息,並把消息存儲在msgp
指向的msgbuf結構中,在成功的讀取了一條消息以後,隊列中的這條消息將被刪除
五、信號量
特點:信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作爲進程間以及同一進程內不同線程之間的同步手段。
與其他進程方式不大相同,主要用途是保護臨界資源,進程可以根據它判定是否能夠訪問某些資源,除了用於訪問控制外,還可以用於進程同步
分類:
二值信號燈:信號燈的值只能取0或1
計數信號燈:信號燈的值可以取任意非負值
創建/打開:int semget(key_t key,int nsems,int semflg)
Key:鍵值,由ftok獲得
Nsems:指定打開或者創建的信號燈集中將包含信號燈的數目
Semflg:標識,同消息隊列
操作:int semop(int semid,struct sembuf *sops,unsigned nsops);
功能:對信號量進行控制
Semid:信號量集的ID
Sops:是一個操作數組,表明要進行什麼操作
Nsops:sops指向的數組的元素個數