轉自:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4077304
1、linux進程間通訊
繼承unix進程間通訊:管道 訊號
AT&T :system V IPC 通訊進程只能在單個電腦 :訊號量 訊息佇列 共用記憶體
BSD:形成了基於socket的進程間通訊機制 TCP/IP
2、管道
(1)無名管道:父子進程
#include <unistd.h>
int pipe(int pipefd[2]);
建立一個管道
fd[0]:讀端
fd[1]:寫端
傳回值:
0:成功
-1:失敗
注意:(1)當管道已經滿了 write pipe 會阻塞
(2) 當管道為空白 read pipe 會阻塞
(2)有名管道:任何進程之間
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
3、訊號
訊號在軟體層次上對中斷的一種類比 非同步通訊方式
中斷:對cpu上的中斷 (硬體)
訊號:對進程的中斷 (軟體)
(1)訊號的來源
(1)程式執行錯誤 如 記憶體訪問越界
(2)其他進程發送
(3)通過控制終端發送 ctrl + c;
(4)子進程結束向父進程發送訊號 SIGCLD
(5)定時器SIGALRM
(2)訊號
kill -l 查看當前系統所有的訊號
(3)訊號處理方式
忽略訊號:對訊號不做任何處理
捕捉訊號:定義處理函數 當訊號發生的時候 執行相應的處理函數
預設操作:在linux系統中間都規定了預設操作
(4)訊號的發送與捕捉
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid:接受訊號的進程的PID
sig:訊號
傳回值:0:成功
-1:出錯
int raise(int sig);
//kill(getpid(),SIGSTOP);
給進程本身發送訊號
(5)定時器的訊號捕捉
unsigned int alarm(unsigned int seconds);
進程定時器
定時時間到 發送SIGALRM
SIGALRM:預設操作:終止進程
傳回值:
在調用之前 如果已經設定過鬧鐘 返回上一次的剩餘時間
否則返回0
-1:出錯
int pause(void);
暫停進程
當收到訊號時 會喚醒進程繼續執行
(6)訊號處理
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
參數:
signum:訊號
handler:SIG_IGN:忽略該訊號
SIG_DFL:採用預設處理訊號
自訂的訊號處理函數的指標
傳回值:返回一個指向訊號處理函數的地址
1)父進程捕捉子進程的訊號
2)從終端輸入文字再次輸出到終端,如果3s沒有輸入就輸出提示
//SIGALRM
alarm()和signal()
4、訊號的阻塞處理
(1)通知系統核心停止向進程發送指定的訊號
(2)核心對進程接收到的相應的訊號進行緩衝
(3)當進程解除相應的訊號的阻塞
設定阻塞的原因:
(1)正在執行訊號處理函數時有其他的訊號到來
(2)訊號處理函數和其他進程對某個共用地區進行讀寫
sigset_t:訊號集
int sigemptyset(sigset_t *set);
把訊號集合清空
int sigfillset(sigset_t *set);
把訊號集合填滿
int sigaddset(sigset_t *set, int signum);
把對應的訊號加到阻塞訊號集合中
int sigdelset(sigset_t *set, int signum);
把對應的訊號從阻塞訊號集合中刪除
int sigismember(const sigset_t *set, int signum);
判斷訊號是否是在阻塞訊號集合中
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
//設定阻塞訊號集合
how:設定訊號阻塞掩碼的方式
SIG_BLOCK:阻塞訊號集
SIG_UNBLOCK:解除訊號集
SIG_SETMASK:設定阻塞掩碼
oldset:舊的阻塞集合
int sigpending(sigset_t *set);
//擷取阻塞的訊號 未決訊號
int flag = 0;
int flag = 1;
while(flag == 0){
int sigsuspend(const sigset_t *mask);
}
//等待訊號
(1)設定訊號掩碼並阻塞進程
(2)收到訊號 恢複原來的屏蔽字
(3)調用進程設定的訊號處理函數
(4)等待訊號處理函數返回後 sigsuspend()返回
原子操作
pause() -----等待訊號(阻塞的訊號除外)
5、訊息佇列
(1)訊息的列表
隊列ID
訊息ID
(2)建立
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
key:指定的ID來產生隊列ID key:ftok()通過轉換檔來擷取
msgflg:IPC_CREAT:建立新的訊息佇列
IPC_EXCL:存在報錯
IPC_NOWAIT:非阻塞
傳回值:返回隊列ID
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:擷取key
pathname:檔案名稱---->inode節點號
proj_id:自己指定
由inode節點號和proj_id合成
65538:0x10002
38:0x26
key: 0x2610002
(4)接收訊息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
參數:
msqid:訊息佇列ID ----- msgget()
msgp:訊息的緩衝區
msgsz:訊息結構的大小
msgtyp:0:接收訊息佇列中的第一個訊息
大於0:接收訊息佇列中第一個為msgtyp的訊息
小於0:接收訊息佇列中第一個不小於msgtyp的絕對值由最小的訊息
msgflg:
0:忽略
MSG_NOERROR:接收的訊息大於size 則訊息就會截短到size位元組 不通知訊息發送進程
IPC_NOWAIT:沒有指定類型的訊息 就會返回錯誤ENOMSG
傳回值:實際接收的位元組數
會刪除對應的訊息
(5)發送訊息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
參數:
msqid:訊息佇列ID ----- msgget()
msgp:發送的訊息緩衝區
struct msgbuf{
long mtype;//訊息類型
char mtext[1];//訊息內容
};
msgsz:訊息內容的大小
msgflg:
IPC_NOWAIT:發送條件不滿足的時 就會立即返回
a):隊列訊息已經滿了
建立2個子進程 父進程負責發送 子進程1:發送類型為1的訊息 子進程2:發送訊息類型為2的訊息
子進程1接收類型為1的訊息
子進程2接收類型為2的訊息
(5)控制函數
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid:訊息佇列ID
cmd:
IPC_STAT:擷取struct msqid_ds結構 儲存到buf
IPC_SET:設定struct msgqid_ds結構
IPC_RMID:刪除訊息佇列
buf:儲存struct msqid_ds結構
傳回值:成功:0(IPC_STAT,IPC_SET,IPC_RMID)
失敗:-1