




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、linux進(jìn)程間通信linux進(jìn)程間通信進(jìn)程間通信IPC(interprocess Communication)提供了一種不同進(jìn)程間可以互相訪問數(shù)據(jù)的方式。相互訪問的數(shù)據(jù)不僅包括程序運行時的適時數(shù)據(jù),也包括對對方代碼段的訪問。進(jìn)程間通信的目的: 1、數(shù)據(jù)傳輸:一個進(jìn)程需要將它的數(shù)據(jù)發(fā)送給另一個進(jìn)程,發(fā)送的數(shù)據(jù)量在一個字節(jié)到幾兆字節(jié)之間。2、共享數(shù)據(jù):多個進(jìn)程想要操作共享數(shù)據(jù),一個進(jìn)程對共享數(shù)據(jù)的修改,別的進(jìn)程應(yīng)該立刻看到。3、通知事件:一個進(jìn)程需要向另一個或一組進(jìn)程發(fā)送消息,通知它(它們)發(fā)生了某種事件(如進(jìn)程終止時要通知父進(jìn)程)。4、資源共享:多個進(jìn)程之間共享同樣的資源。為了作到這一點,需要
2、內(nèi)核提供鎖和同步機(jī)制。5、進(jìn)程控制:有些進(jìn)程希望完全控制另一個進(jìn)程的執(zhí)行(如Debug進(jìn)程),此時控制進(jìn)程希望能夠攔截另一個進(jìn)程的所有異常,并能夠及時知道它的狀態(tài)改變。linux進(jìn)程間通信發(fā)展歷史linux進(jìn)程間通信(IPC)由以下幾部分發(fā)展而來:linux進(jìn)程間通信方式目前Linux 中使用較多的進(jìn)程間通信方式:(1)管道(Pipe)及有名管道(named pipe) :管道可用于具有親緣關(guān)系進(jìn)程間的通信;有名管道,除具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信。(2)信號(Signal) :信號是在軟件層次上對中斷機(jī)制的一種模擬,它是比較復(fù)雜的通信方式,用于通知接受進(jìn)程有某事件發(fā)
3、生,一個進(jìn)程收到一個信號與處理器收到一個中斷請求效果上可以說是一樣的。(3)消息(message)隊列:消息隊列是消息的鏈接表,包括 Posix 消息隊列 systemV 消息隊列。它克服了前兩種通信方式中信息量有限的缺點,具有寫權(quán)限的進(jìn)程可以向消息隊列中按照一定的規(guī)則添加新消息;對消息隊列有讀權(quán)限的進(jìn)程則可以從消息隊列中讀取消息。linux進(jìn)程間通信(4)共享內(nèi)存(shared memory) :可以說這是最有用的進(jìn)程間通信方式。它使得多個進(jìn)程可以訪問同一塊內(nèi)存空間,不同進(jìn)程可以及時看到對方進(jìn)程中對共享內(nèi)存中數(shù)據(jù)的更新。這種通信方式需要依靠某種同步機(jī)制,如互斥鎖和信號量等。(5)信號量(se
4、maphore) :主要作為進(jìn)程間以及同一進(jìn)程不同線程之間的同步手段。(6)套接字(Socket) :這是一種更為一般的進(jìn)程間通信機(jī)制,它可用于不同機(jī)器之間的進(jìn)程間通信,應(yīng)用常廣泛。管道通信管道通信是linux 中比較常見,也比較原始的通信方式之一,它實現(xiàn)了數(shù)據(jù)以一種數(shù)據(jù)流的方式,在多進(jìn)程間流動。管道:是指用于連接一個讀進(jìn)程和一個寫進(jìn)程,以實現(xiàn)它們之間通信的共享文件,又稱pipe文件。 管道是單向的、先進(jìn)先出的、無結(jié)構(gòu)的、固定大小的字節(jié)流,它把一個進(jìn)程的標(biāo)準(zhǔn)輸出和另一個進(jìn)程的標(biāo)準(zhǔn)輸入連接在一起。 寫進(jìn)程在管道的尾端寫入數(shù)據(jù),讀進(jìn)程在管道的首端讀出數(shù)據(jù)。 數(shù)據(jù)讀出后將從管道中移走,其它讀進(jìn)程都不
5、能再讀到這些數(shù)據(jù)。 管道提供了簡單的流控制機(jī)制。進(jìn)程試圖讀空管道時,在有數(shù)據(jù)寫入管道前,進(jìn)程將一直阻塞。同樣,管道已經(jīng)滿時,進(jìn)程再試圖寫管道,在其它進(jìn)程從管道中移走數(shù)據(jù)之前,寫進(jìn)程將一直阻塞。管道分類: 無名管道: (匿名管道)在系統(tǒng)中沒有實名,不能在文件系統(tǒng)中以任何方式看到該管道,它只是進(jìn)程的一種資源,會隨著進(jìn)程的結(jié)束而被系統(tǒng)清除。 有名管道:也稱為FIFO管道,是一種文件類型,在文件系統(tǒng)中可以查看到。7匿名管道(pipe) 對匿名管道兩端進(jìn)程而言,是一個只存在于內(nèi)存的特殊文件 匿名管道是半雙工的,數(shù)據(jù)只能向一個方向流動 一個進(jìn)程將數(shù)據(jù)寫入管道,另一進(jìn)程從管道中讀取數(shù)據(jù) 寫入的內(nèi)容添加在管道
6、緩沖區(qū)的末尾,每次都是從緩沖區(qū)頭部讀出數(shù)據(jù) 雙向通信的建立 需要建立起兩個管道 使用限制 只能用于具有親緣關(guān)系的進(jìn)程之間 如父子進(jìn)程或兄弟進(jìn)程之間管道通信管道通信8匿名管道的建立 基本函數(shù) int pipe(int fd2); 參數(shù)說明 fd2描述管道兩端 fd0只能用于讀,稱為管道讀端 fd1只能用于寫,稱為管道寫端 若試圖從寫端讀,或者向讀端寫都將導(dǎo)致錯誤發(fā)生 返回值 成功時返回0,失敗時返回-1 說明 基本文件I/O函數(shù)都可用于管道 如close()、read()、write()等 低層系統(tǒng)調(diào)用 sys_pipe( )-do_pipe()管道通信管道通信9匿名管道的讀操作 進(jìn)程調(diào)用rea
7、d()系統(tǒng)調(diào)用 內(nèi)核最終調(diào)用與該文件描述符相關(guān)的文件操作表中所找到的read()方法 在管道情形下,read方法將指向pipe_read()函數(shù) 該系統(tǒng)調(diào)用可能以兩種方式阻塞當(dāng)前進(jìn)程 系統(tǒng)調(diào)用開始時管道緩沖區(qū)為空 管道緩沖區(qū)沒有包含所請求的字節(jié)(n個字節(jié)),寫進(jìn)程在等待緩沖區(qū)的空間時曾經(jīng)被置為睡眠10匿名管道的寫操作 進(jìn)程調(diào)用write()系統(tǒng)調(diào)用 內(nèi)核最終調(diào)用pipe_write()函數(shù) 如果管道沒有讀進(jìn)程,寫進(jìn)程發(fā)送SIGPIPE信號 管道緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程將試圖寫入數(shù)據(jù) 如果讀進(jìn)程不讀出管道緩沖區(qū)中的數(shù)據(jù),那么寫操作將一直阻塞匿名管道示例一#include#include#inc
8、ludeint main(void) int fd2; char str256; if( pipe(fd)0 ) perror(pipe); exit(1); write(fd1, Create the pipe successfully!n, 31); read(fd0, str, sizeof(str); printf(%sn,str); close(fd0); close(fd1); return 0; 單個進(jìn)程中的管道幾乎沒有任何用處。通常,調(diào)用 p i p e的進(jìn)程接著調(diào)用 f o r k,這樣就創(chuàng)建了從父進(jìn)程到子進(jìn)程或反之的 I P C通道。 f o r k之后做什么取決于我們想要
9、有的數(shù)據(jù)流的方向。對于從父進(jìn)程到子進(jìn)程的管道,父進(jìn)程關(guān)閉管道的讀端(f d 0 ) ,子進(jìn)程則關(guān)閉寫端(f d 1 ) 。對于從子進(jìn)程到父進(jìn)程的管道,父進(jìn)程關(guān)閉 f d 1 ,子進(jìn)程關(guān)閉f d 0 。12#include#include#include#define BUFSZ 256int main(void) int fd2; char bufBUFSZ; pid_t pid; int len; if( pipe(fd)0 ) perror(failed to pipe); exit(1); if( (pid = fork() 0) printf(This is farther, writ
10、e to fd1n,fd0,fd1); close(fd0); write(fd1, farther write,child readn, 25); exit(0); else printf(This is child ,read from fd0n); close(fd1); read(fd0, buf, BUFSZ); printf(%sn, buf); return 0;匿名管道-父子進(jìn)程間通信匿名管道操作基本流程 管道操作的基本流程:1)使用pipe函數(shù)創(chuàng)建管道;2)用fork函數(shù)創(chuàng)建一個子進(jìn)程;3)關(guān)閉父子進(jìn)程中不需要的文件描述符,使用管道進(jìn)行通信;由于以上對管道的操作是比較規(guī)范,也
11、比較常用。所以在ANSI C中將以上操作定義在兩個標(biāo)準(zhǔn)庫函數(shù)中,分別是popen和pclose函數(shù)。 FILE * popen(const char * command, const char * type) ; int pclose(FILE * f p) ; 參數(shù)command是一個在shell中可以運行的命令字符串的指針; 參數(shù)type是一個字符指針,這個參數(shù)只有兩種值,分別是r和w,分別對應(yīng)popen函數(shù)的返回值是一個讀打開文件指針,還是寫打開文件指針。函數(shù)失敗返回NULL,并設(shè)置出錯變量errno。pclose函數(shù)的參數(shù)fp是一個popen打開的文件描述符,函數(shù)失敗時返回-1。#in
12、clude #include #include #include #include #define BUFES PIPE_BUFint main(void) FILE *fp; char *cmd = ls -l; char bufBUFES; if(fp = popen(cmd, r) = NULL) perror(failed to openn); exit(1); while(fgets(buf, BUFES, fp) != NULL) printf(%sn, buf); pclose(fp); exit(0);Popen示例16有名管道 匿名管道缺點 沒有名字,只能用于具有親緣關(guān)系的進(jìn)
13、程間通信 FIFO(有名管道) 嚴(yán)格遵循先進(jìn)先出的讀寫規(guī)則 有名字,F(xiàn)IFO的名字包含在系統(tǒng)的目錄樹結(jié)構(gòu)中,支持無親緣關(guān)系的進(jìn)程按名字訪問 類似管道,在文件系統(tǒng)中不存在數(shù)據(jù)塊,而是與一塊內(nèi)核緩沖區(qū)相關(guān)聯(lián) read和write操作也由pipe_read()和pipe_write() 實現(xiàn) 與匿名管道主要區(qū)別 FIFO索引節(jié)點出現(xiàn)在系統(tǒng)目錄樹上而不是pipefs特殊文件系統(tǒng)中 FIFO是一種雙向通信管道,可以以讀/寫模式打開一個FIFO17有名管道的建立 基本函數(shù) int mkfifo(const char * pathname, mode_t mode); 參數(shù)說明 pathname:創(chuàng)建的FI
14、FO名字 mode:規(guī)定FIFO的讀寫權(quán)限 返回值 成功時返回0 失敗時返回-1 若路徑名存在,則返回EEXIST錯誤 說明 一般文件的I/O函數(shù)都可用于管道,如open(), close(), read(), write()等。18有名管道的open() 打開規(guī)則 為讀操作而打開FIFO文件 若已有進(jìn)程為寫而打開該FIFO,則當(dāng)前打開操作將成功返回 否則,可能阻塞直到有相應(yīng)進(jìn)程為寫而打開該FIFO(當(dāng)前打開操作設(shè)置未設(shè)置O_NONBLOCK標(biāo)志) 或立即返回(當(dāng)前打開操作設(shè)置O_NONBLOCK標(biāo)志) 為寫操作而打開FIFO文件 如果已經(jīng)有進(jìn)程為讀而打開該FIFO,則當(dāng)前打開操作將成功返回
15、否則,可能阻塞直到有相應(yīng)進(jìn)程為讀而打開該FIFO(當(dāng)前打開操作未設(shè)置O_NONBLOCK標(biāo)志) 或者,返回ENXIO錯誤(當(dāng)前打開操作設(shè)置O_NONBLOCK標(biāo)志) 實例:1,mkfifo testfifo 建立有名管道文件testfifo;2,ls testfifo 向有名管道文件寫入”ls”命令顯示的內(nèi)容;3,cat testfifo 用”cat”命令讀取”testfifo”文件中的內(nèi)容;19有名管道示例創(chuàng)建有名管道#include#include#include#include#include#include#include#includeint main(int argc, char*
16、 argv)/mode_t mode = 0666;mode_t mode = O_NONBLOCK;if( argc!=2 ) printf(USEMSG: create_fifo fifonamen); exit(1);if(mkfifo(argv1,mode)0) perror(failed to mkfifo); exit(1);elseprintf(you successfully create a FIFO name is:%sn,argv1);exit(0); 20有名管道舉例讀有名管道 #include #include #include #include #include #
17、include #include #include #define BUFES PIPE_BUF int main(void) int fd; int len; char bufBUFES; if(fd=open(testfifo,O_RDONLY)0) printf(read: %s,buf); close(fd); return 0; 21有名管道示例寫有名管道#include#include#include#include#include#include#include#include#define BUFES PIPE_BUFint main(void) int fd; int n,
18、i; if( (fd=open(testfifo,O_WRONLY) 0) perror(open); exit(1); for(i=0; i10; i+) if ( write(fd,message n,9)0 ) perror(write); exit(1); close(fd); return 0;22信號的本質(zhì) 信號是一種進(jìn)程間異步通信機(jī)制,可以看作是異步通知,通知接收信號的進(jìn)程有哪些事情發(fā)生了。在實現(xiàn)上是一種軟中斷。是對中斷的模擬,也稱軟中斷信號或軟中斷。 信號可以導(dǎo)致一個正在運行的進(jìn)程被異步打斷,讓進(jìn)程知道已經(jīng)發(fā)生了一個特定事件; 強(qiáng)迫進(jìn)程執(zhí)行自身代碼中的信號處理程序; 發(fā)給非運行
19、進(jìn)程的信號必須由內(nèi)核保存,直到進(jìn)程恢復(fù)執(zhí)行; 阻塞一個信號要求信號的傳遞被延遲,直到隨后解除阻塞; 每個信號都有名字,這些名字都是以SIG開頭; 不存在編號為0的信號。信號來源硬件來源硬件操作,如按Ctrl+C硬件故障軟件來源常用信號發(fā)送函數(shù),如kill(), raise(), alarm()非法運算(浮點運算溢出或內(nèi)存訪問錯誤等也可產(chǎn)生信號24信號分類 不可靠信號 信號值小于SIGRTMIN; 進(jìn)程每次處理信號后,將信號響應(yīng)函數(shù)設(shè)置為默認(rèn)動作,需調(diào)用signal() 重新安裝信號 ; 非實時信號都是不可靠信號,不支持排隊,信號可能丟失; 可靠信號 信號值介于SIGRTMIN和SIGRTMAX
20、之間; 新信號安裝函數(shù)sigaction()和信號發(fā)送函數(shù)sigqueue(); 實時信號都是可靠信號,支持排隊;信號通信信號通信25進(jìn)程對信號的響應(yīng)方式 忽略信號 進(jìn)程忽略接收到的信號,不做任何處理; SIGKILL和SIGSTOP不能忽略; 不能為SIGKILL和SIGSTOP設(shè)置新的信號處理函數(shù)。 捕獲信號 類似中斷處理程序,一旦捕獲到相應(yīng)信號,執(zhí)行對應(yīng)的信號處理函數(shù); 進(jìn)程可通過signal()/sigaction()指定進(jìn)程對某個信號的處理行為; 缺省操作 Linux內(nèi)核為信號提供默認(rèn)處理程序處理;26常見信號1SIGHUP從終端上發(fā)出的結(jié)束信號從終端上發(fā)出的結(jié)束信號2SIGINT來
21、自鍵盤的中斷信號(來自鍵盤的中斷信號(Ctrl-c)3SIGQUIT來自鍵盤的退出信號(來自鍵盤的退出信號(Ctrl-)8SIGSTOP進(jìn)程收到該信號后會暫停執(zhí)行,進(jìn)入暫停態(tài)進(jìn)程收到該信號后會暫停執(zhí)行,進(jìn)入暫停態(tài)9SIGKILL立即結(jié)束程序,立即結(jié)束程序,不能被阻塞不能被阻塞,處理和忽略,處理和忽略14 SIGALRM 進(jìn)程的定時器到期時,發(fā)送該信號進(jìn)程的定時器到期時,發(fā)送該信號18 SIGCONT處于阻塞狀態(tài)的進(jìn)程收到該信號后會繼續(xù)執(zhí)處于阻塞狀態(tài)的進(jìn)程收到該信號后會繼續(xù)執(zhí)行行17 SIGCHLD子進(jìn)程退出時給父進(jìn)程發(fā)送該信號子進(jìn)程退出時給父進(jìn)程發(fā)送該信號27信號生命周期信號誕生 觸發(fā)信號的事
22、件發(fā)生(如檢測到硬件異常、定時器超時以及調(diào)用信號發(fā)送函數(shù)kill()或sigqueue()等)。信號在進(jìn)程中注冊 內(nèi)核更新目標(biāo)進(jìn)程的數(shù)據(jù)結(jié)構(gòu),將信號加入進(jìn)程的未決信號集,并將信號所攜信息保存到某個sigqueue結(jié)構(gòu)中 對實時信號,不管其是否已在進(jìn)程中注冊,都被再次注冊 對非實時信號,若該信號已在進(jìn)程中注冊,則將其丟棄信號在進(jìn)程中注銷 進(jìn)程從核心空間返回用戶空間時都檢測是否有信號等待處理 若存在等待處理且未被阻塞的未決信號,則將其在未決信號鏈中占有的結(jié)構(gòu)卸掉(對實時進(jìn)程只刪除sigqueue結(jié)構(gòu))信號處理函數(shù)執(zhí)行完畢 執(zhí)行相應(yīng)信號處理函數(shù)或改變目標(biāo)進(jìn)程的執(zhí)行狀態(tài)28信號在進(jìn)程中注冊 進(jìn)程的ta
23、sk_struct結(jié)構(gòu)中有關(guān)于本進(jìn)程中未決信號的數(shù)據(jù)成員: struct sigpending中第三個成員signal是進(jìn)程中所有未決信號集,第一、第二個成員分別指向一個sigqueue類型的鏈表的(稱之為“未決信號信息鏈”)的首尾,該鏈中的每個sigqueue結(jié)構(gòu)包含一個特定信號所攜帶的信息,并指向下一個sigqueue結(jié)構(gòu):struct sigpending pending;struct sigpendingstruct sigqueue *head, *tail;sigset_t signal;struct sigqueuestruct sigqueue *next;siginfo_t
24、info;信號在進(jìn)程中注銷 在目標(biāo)進(jìn)程執(zhí)行過程中,會檢測是否有信號等待處理(每次從系統(tǒng)空間返回到用戶空間時都做這樣的檢查)。如果存在未決信號等待處理且該信號沒有被進(jìn)程阻塞,則在運行相應(yīng)的信號處理函數(shù)前,進(jìn)程會把信號在未決信號鏈中占有的結(jié)構(gòu)卸掉。是否將信號從進(jìn)程未決信號集中刪除對于實時與非實時信號是不同的。對于非實時信號來說,由于在未決信號信息鏈中最多只占用一個sigqueue結(jié)構(gòu),因此該結(jié)構(gòu)被釋放后,應(yīng)該把信號在進(jìn)程未決信號集中刪除(信號注銷完畢);而對于實時信號來說,可能在未決信號信息鏈中占用多個sigqueue結(jié)構(gòu),因此應(yīng)該針對占用sigqueue結(jié)構(gòu)的數(shù)目區(qū)別對待:如果只占用一個sigq
25、ueue結(jié)構(gòu)(進(jìn)程只收到該信號一次),則應(yīng)該把信號在進(jìn)程的未決信號集中刪除(信號注銷完畢)。否則,不應(yīng)該在進(jìn)程的未決信號集中刪除該信號(信號注銷完畢)。 進(jìn)程在執(zhí)行信號相應(yīng)處理函數(shù)之前,首先要把信號在進(jìn)程中注銷。30信號處理函數(shù) 信號發(fā)送函數(shù) kill(), sigqueue(), raise(), alarm(), setitimer(), pause(),abort() 信號安裝函數(shù) signal(), sigaction() 信號集操作函數(shù) sigemptyset(), sigfillset(), sigaddset(), sigdelset(), sigismember()31信號發(fā)送
26、函數(shù)kill()#include #include int kill(pid_t pid,int signo) 功能 向進(jìn)程或進(jìn)程組發(fā)送一個信號 (成功返回 0; 否則,返回 -1 )參數(shù)說明 pid:接收信號的進(jìn)程(組)的進(jìn)程號 pid0:發(fā)送給進(jìn)程號為pid的進(jìn)程 pid=0:發(fā)送給當(dāng)前進(jìn)程所屬進(jìn)程組里的所有進(jìn)程 pid=-1:發(fā)送給除1號進(jìn)程和自身以外的所有進(jìn)程 pid-1:發(fā)送給屬于進(jìn)程組-pid的所有進(jìn)程 signo:發(fā)送的信號 Signo = 0:不發(fā)送信號,可用于檢查目標(biāo)進(jìn)程是否存在,以及當(dāng)前進(jìn)程是否具有向目標(biāo)進(jìn)程發(fā)送信號的權(quán)限(root權(quán)限的進(jìn)程可以向任何進(jìn)程發(fā)送信號,非roo
27、t權(quán)限的進(jìn)程只能向?qū)儆谕粋€session或者同一個用戶的進(jìn)程發(fā)送信號)。#include #include #include #include #include int main( void ) pid_t childpid; int status; int retval; childpid = fork(); if ( -1 = childpid ) perror( fork() ); exit( EXIT_FAILURE ); else if ( 0 = childpid ) puts( In child process ); sleep( 100 );/讓子進(jìn)程睡眠,看看父進(jìn)程的行為
28、exit(EXIT_SUCCESS); else if ( 0 = (waitpid( childpid, &status, WNOHANG ) retval = kill( childpid,SIGKILL ); if ( retval ) puts( kill failed. ); perror( kill ); waitpid( childpid, &status, 0 ); else printf( %d killedn, childpid ); exit(EXIT_SUCCESS); 33信號發(fā)送函數(shù)sigqueue()#include #include int si
29、gqueue(pid_t pid, int signo, const union sigval sigval_t) 調(diào)用成功返回 0;否則,返回 -1。功能 主要針對實時信號,支持帶有參數(shù)信號,與函數(shù)sigaction()配合使用參數(shù)說明 pid:接收信號的進(jìn)程ID signo:待發(fā)送信號 sigval_t:信號傳遞的參數(shù)(4字節(jié))說明 調(diào)用sigqueue()時,sigval_t被拷貝到信號處理函數(shù) sigqueue()發(fā)送非實時信號時 sigval_t包含的信息仍然能夠傳遞給信號處理函數(shù) 仍然不支持排隊,所有相同信號都被合并為一個信號34sigqueue()向信號傳遞附加消息的流程 sig
30、queue()的第三個參數(shù)是sigval聯(lián)合數(shù)據(jù)結(jié)構(gòu) 調(diào)用sigqueue()時,該數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)將被拷貝到信號處理函數(shù)sigaction()的第二個參數(shù) 這樣,就可在發(fā)送信號的同時讓信號傳遞一些附加信息 typedef union sigval int sival_int; void *sival_ptr; sigval_t;35Kill()與sigqueue()區(qū)別 sigqueue()比kill()傳遞更多的附加信息 sigqueue()只能向一個進(jìn)程發(fā)送信號信號通信信號通信36信號發(fā)送函數(shù)raise()#include int raise(int signo) 功能 向自身發(fā)送信號
31、參數(shù)說明 signo:發(fā)送的信號 signo=0:不發(fā)送信號返回值 成功時,返回0 錯誤時,返回-1說明 raise()可以通過kill( )實現(xiàn),raise(signo)等價于 kill(getpid( ), signo);信號通信信號通信 #include #include int main(void) printf(kill myself!n); raise(SIGKILL); printf(can you see this?n); return 0; 38信號發(fā)送函數(shù)alarm()#include unsigned int alarm(unsigned int seconds) 功能
32、設(shè)置定時器,當(dāng)計時時間到達(dá)時,向進(jìn)程發(fā)出SIGALRM信號參數(shù)說明 seconds:等待秒數(shù) seconds為0時,取消先前設(shè)置的鬧鐘,返回鬧鐘剩余時間u若之前未設(shè)鬧鐘,則返回0說明 alarm()只發(fā)送一次信號 若需重復(fù)設(shè)定定時器,則要多次調(diào)用alarm()函數(shù) 信號通信信號通信#include #include #include #include #include void handler() printf(hellonn);main()int i;signal(SIGALRM,handler);alarm(5);for(i=1;i7;i+)printf(sleep %d n,i);sle
33、ep(1);40信號發(fā)送函數(shù)setitimer()函數(shù)原型 int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); 參數(shù)說明 which:邏輯定時器類型 ITIMER_REAL:按實際時間計時,計時到達(dá)時向進(jìn)程發(fā)送SIGALRM信號。 ITIMER_VIRTUAL:計算進(jìn)程在用戶態(tài)執(zhí)行的時間,計時到達(dá)將發(fā)送SIGVTALRM信號給進(jìn)程。 ITIMER_PROF:計算進(jìn)程在用戶態(tài)和核心態(tài)的總時間。計時到達(dá)將發(fā)送SIGPROF信號給進(jìn)程。u與ITIMER_VIRTUAL是一對,該定時器經(jīng)常
34、用來統(tǒng)計進(jìn)程在用戶態(tài)和核心態(tài)花費的時間 value:指明定時器的時間 ovalue:如果不為空,則保存上次調(diào)用設(shè)定的值功能 指定一段時間后,執(zhí)行某個function; 每間格一段時間就執(zhí)行某個function41信號發(fā)送函數(shù)setitimer() (續(xù))返回值 成功時,返回0 錯誤時,返回-1struct itimerval結(jié)構(gòu)定義struct itimerval struct timeval it_interval; /*定時器周期*/ struct timeval it_value; /*定時器剩的時間,為0時發(fā)信號*/; struct timeval結(jié)構(gòu)定義struct timeval
35、long tv_sec; /*秒*/ long tv_usec; /*微秒,1秒=1000000微秒*/; it_value為為0是不會觸發(fā)信號的,所以要能觸發(fā)信號,是不會觸發(fā)信號的,所以要能觸發(fā)信號,it_value得大于得大于0;如果如果it_interval為零,只會延時,不會定時(也就是說只會觸發(fā)一次為零,只會延時,不會定時(也就是說只會觸發(fā)一次信號信號)。信號通信信號通信42信號發(fā)送函數(shù)setitimer()示例 #include #include #include void signalHandler(int signo) switch (signo) case SIGALRM:
36、printf(Caught the SIGALRM signal!n); break; int main(int argc, char *argv) signal(SIGALRM, signalHandler); struct itimerval new_value, old_value; new_value.it_value.tv_sec = 1; new_value.it_value.tv_usec = 0; new_value.it_interval.tv_sec = 2; new_value.it_interval.tv_usec = 0; setitimer(ITIMER_REAL,
37、 &new_value, &old_value); for(;); return 0; 43信號發(fā)送函數(shù)pause() 功能 使當(dāng)前進(jìn)程暫停,進(jìn)入睡眠狀態(tài),直到被信號所中斷,即將進(jìn)程掛起等待信號到來。 函數(shù)原型 int pause(void); 返回值 -1 舉例 使用alarm( )和pause( )實現(xiàn)sleep( )功能44信號發(fā)送函數(shù)pause()示例信號的安裝(設(shè)置信號關(guān)聯(lián)動作)信號的安裝(設(shè)置信號關(guān)聯(lián)動作) 如果進(jìn)程要處理某一信號,那么就要在進(jìn)程中安裝該信號。安裝信號主要用來確定信號值及進(jìn)程針對該信號值的動作之間的映射關(guān)系,即進(jìn)程將要處理哪個信處理哪個信號號;該信號
38、被傳遞給進(jìn)程時,將執(zhí)行何種操作執(zhí)行何種操作。 linux主要有兩個函數(shù)實現(xiàn)信號的安裝:signal()、sigaction()。其中signal()在非可靠信號系統(tǒng)調(diào)用的基礎(chǔ)上實現(xiàn), 是庫函數(shù)。它只有兩個參數(shù)兩個參數(shù),不支持信號傳遞信息,主要是用于前32種非實時信號的安裝;而sigaction()是較新的函數(shù)(由兩個系統(tǒng)調(diào)用實現(xiàn):sys_signal以及sys_rt_sigaction),有三個參數(shù)有三個參數(shù),支持信號傳遞信息,主要用來與 sigqueue() 系統(tǒng)調(diào)用配合使用,當(dāng)然,sigaction()同樣支持非實時信號的安裝。sigaction()優(yōu)于signal()主要體現(xiàn)在支持信號帶
39、有參數(shù)。46信號安裝函數(shù)signal() 原型定義 void (*signal(int signum, void (*handler)(int)(int); 參數(shù)說明 signum:需要安裝的信號 handler:與安裝信號相關(guān)的處理函數(shù),可以是SIG_IGN或SIG_DFL SIG_IGN:忽略該信號 SIG_DFL:執(zhí)行默認(rèn)操作函數(shù) 返回值 成功時,返回新安裝信號處理函數(shù)handler的值 失敗時,返回SIG_ERR 底層系統(tǒng)調(diào)用 sys_signal(int sig, _sighandler_t handler)47信號安裝函數(shù)signal()示例#include #include #i
40、nclude #include void sig_usr(int sig);int main(int argc, char* argv) int i=0; if(signal(SIGUSR1, sig_usr) = SIG_ERR)printf(Cant catch SIGUSR1n); if(signal(SIGUSR2, sig_usr) = SIG_ERR) printf(“Cant catch SIGUSR2n”); while(1) printf(%2dn, i); pause(); i+; return 0;void sig_usr(int sig) if(sig = SIGUSR
41、1) printf(Received SIGUSR1n); else if(sig = SIGUSR2) printf(Received SIGUSR2n); else printf(Undeclared signal %d n,sig);執(zhí)行: Gcc signal.c o signal ./signal&(以后臺程序運行,并顯示pid) Kill SIGUSR1 pid49信號安裝函數(shù)sigaction()原型定義int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); sig
42、action函數(shù)用于設(shè)定進(jìn)程接收到特定信號后的行為。第一個參數(shù)為信號的值,可以為除SIGKILL及SIGSTOP外的任何一個特定有效的信號(為這兩個信號定義自己的處理函數(shù),將導(dǎo)致信號安裝錯誤)。第二個參數(shù)是指向結(jié)構(gòu)sigaction的一個實例的指針,在結(jié)構(gòu)sigaction的實例中,指定了對特定信號的處理,如果為空,進(jìn)程會以缺省方式對信號處理;第三個參數(shù)oldact指向的對象用來保存原來對相應(yīng)信號的處理,可指定oldact為NULL。如果把第二、第三個參數(shù)都設(shè)為NULL,那么該函數(shù)可用于檢查信號的有效性。第二個參數(shù)最為重要,其中包含了對指定信號的處理、信號所傳遞的信息、信號處理函數(shù)執(zhí)行過程中應(yīng)
43、屏蔽掉哪些函數(shù)等等。底層系統(tǒng)調(diào)用sys_sigaction(int sig, const struct old_sigaction _user *act, struct old_sigaction _user *oact) sigaction結(jié)構(gòu)定義如下: sa_restorer,已過時,POSIX不支持它,不應(yīng)再被使用。 聯(lián)合數(shù)據(jù)結(jié)構(gòu)中的兩個元素_sa_handler以及*_sa_sigaction指定信號關(guān)聯(lián)函數(shù),即用戶指定的信號處理函數(shù)。除了可以是用戶自定義的處理函數(shù)外,還可以為SIG_DFL(采用缺省的處理方式),也可以為SIG_IGN(忽略信號)。 struct sigaction
44、union _sighandler_t _sa_handler; void (*_sa_sigaction)( int, struct siginfo *, void *); _u sigset_t sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); 由_sa_handler 指定的處理函數(shù)只有一個參數(shù),即信號值,所以信號不能傳遞除信號值之外的任何信息; 由_sa_sigaction 指定的信號處理函數(shù)帶有三個參數(shù),是為實時信號而設(shè)的(當(dāng)然同樣支持非實時信號),它指定一個3參數(shù)信號處理函數(shù)。第一個參數(shù)為信號值,第三個參數(shù)沒有使
45、用(posix沒有規(guī)范使用該參數(shù)的標(biāo)準(zhǔn)),第二個參數(shù)是指向siginfo_t 結(jié)構(gòu)的指針,結(jié)構(gòu)中包含信號攜帶的數(shù)據(jù)值,參數(shù)所指向的結(jié)構(gòu)如下:siginfo_t int si_signo; /* 信號值,對所有信號有意義*/ int si_errno; /* errno值,對所有信號有意義*/ int si_code; /* 信號產(chǎn)生的原因,對所有信號有意義*/ pid_t si_pid; /* 發(fā)送信號的進(jìn)程ID,對實時信號以及SIGCHLD有 意義 */ uid_t si_uid; /* 發(fā)送信號進(jìn)程的真實用戶ID,對kill(2),實時信號以及SIGCHLD有意義 */ int si_st
46、atus; /* 退出狀態(tài),對SIGCHLD有意義*/ clock_t si_utime; /* 用戶消耗的時間,對SIGCHLD有意義 */ clock_t si_stime; /* 內(nèi)核消耗的時間,對SIGCHLD有意義 */ sigval_t si_value; /* 信號值,對所有實時有意義,是一個聯(lián)合數(shù)據(jù)結(jié)構(gòu), /*可以為一個整數(shù)(由si_int標(biāo)示,也可以為一個指針,由si_ptr標(biāo)示)*/ void * si_addr; /* 觸發(fā)fault的內(nèi)存地址,對SIGILL,SIGFPE,SIGSEGV,SIGBUS 信號有意義*/ int si_band; /* 對SIGPOLL信號
47、有意義 */ int si_fd; /* 對SIGPOLL信號有意義 */ sa_mask:信號的集合。指定在信號處理程序執(zhí)行過程中,哪些信號應(yīng)當(dāng)被阻塞。缺省情況下當(dāng)前信號本身被阻塞,防止信號的嵌套發(fā)送。 注:sigaction()安裝信號的處理函數(shù)執(zhí)行過程中由sa_mask指定的信號才被阻塞。 sa_flags用于更改指定信號的行為。比較重要的標(biāo)志位是SA_SIGINFO,當(dāng)設(shè)定了該標(biāo)志位時,表示信號附帶的參數(shù)可以被傳遞到信號處理函數(shù)中,因此,應(yīng)該為sigaction結(jié)構(gòu)中的sa_sigaction指定處理函數(shù),而不應(yīng)該為sa_handler指定信號處理函數(shù),否則,設(shè)置該標(biāo)志變得毫無意義。即
48、使為sa_sigaction指定了信號處理函數(shù),如果不設(shè)置SA_SIGINFO,信號處理函數(shù)同樣不能得到信號傳遞過來的數(shù)據(jù),在信號處理函數(shù)中對這些信息的訪問都將導(dǎo)致段錯誤(Segmentation fault)。54信號安裝函數(shù)sigaction()示例一#include #include #include #include void myFun(int sig);int main(int argc, char* argv) struct sigaction act, oldact; act.sa_handler = myFun; sigemptyset(&act.sa_mask);
49、act.sa_flags = 0; sigaction(SIGUSR1, &act, &oldact); while(1) printf(Hello world!n); pause(); void myFun(int sig) printf(I got a signal:%dn,sig); Gcc sigacton1.c o sigaction ./sigaction& Kill SIGUSR1 pid信號安裝函sigaction()數(shù)示例二#include #include #include #include void func(int signo, siginfo_
50、t *info, void *p) printf(signo = %dn, signo); printf(sender pid = %dn, info-si_pid);int main() struct sigaction act, oldact; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; act.sa_sigaction = func; sigaction(SIGUSR1, &act, &oldact); while(1) printf(pid is %d hello!n,getpid(); pause
51、(); 在另外一個終端發(fā)送信號給當(dāng)前進(jìn)程sigqueue()函數(shù)調(diào)用示例在不同進(jìn)程間傳遞整型參數(shù).信號接收程序 #include #include #include #include #include void myFun(int, siginfo_t*, void* myfun); int main(int argc, char* argv) struct sigaction act; int sig; pid_t pid; pid = getpid(); printf(pid is%dn,pid); sigemptyset(&act.sa_mask); act.sa_sigacti
52、on = myFun; act.sa_flags = SA_SIGINFO;56 if(sigaction(SIGUSR1, &act, NULL)si_int); printf(Recv signum is%dn,signo); /raise(SIGKILL); sigqueue()函數(shù)調(diào)用示例在不同進(jìn)程間傳遞整型參數(shù).信號發(fā)送程序#include #include #include #include #include #include main(int argc, char* argv) pid_t pid; int signum; union sigval mysigval; p
53、id = (pid_t)atoi(argv1); mysigval.sival_int = 8; if(sigqueue(pid, SIGUSR1, mysigval)=-1) printf(send errorn); sleep(2); return 0;57signal()與sigaction()的區(qū)別 不同點 signal() 安裝的信號不能向信號處理函數(shù)傳遞信息 sigaction() 可設(shè)置進(jìn)程的信號掩碼,返回設(shè)置之前的sigaction結(jié)構(gòu) 安裝的信號可以向信號處理函數(shù)傳遞信息 相同點 都可以為指定的信號設(shè)置信號處理函數(shù) 共用同一個內(nèi)核函數(shù)do_sigaction()5859信號集
54、操作函數(shù)信號集定義函數(shù)原型 int sigemptyset(sigset_t *set); 初始化信號集合set,將set設(shè)置為空 int sigfillset(sigset_t *set); 初始化信號集合,將信號集set設(shè)置為包含所有信號的集合 int sigaddset(sigset_t *set, int signo); 將信號signo加入到信號集set中 int sigdelset(sigset_t *set, int signo); 將信號signo從信號集set中刪除 int sigismember(sigset_t *set, int signo); 查詢信號signo是否在
55、信號集set中 60信號操作函數(shù)sigprocmask( )功能 通過信號集set修改進(jìn)程的信號阻塞集函數(shù)原型 int sigprocmask(int how, const sigset_t *set, sigset_t *oset);參數(shù) how:函數(shù)操作方式 SIG_BLOCK:增加一個信號集到當(dāng)前進(jìn)程的阻塞集中 SIG_UNBLOCK:從當(dāng)前阻塞集中刪除一個信號集 SIG_SETMASK:將當(dāng)前信號集設(shè)置為信號阻塞集合 set:當(dāng)前進(jìn)程的信號集 oset:保存當(dāng)前進(jìn)程的信號阻塞集說明 在使用之前需先設(shè)置好信號集合set61其他信號處理函數(shù) sigpending(sigset_t *set
56、) 獲取當(dāng)前進(jìn)程的未決信號集 set保存返回結(jié)果 sigsuspend(const sigset_t *mask) 在接收到某個信號之前,臨時用mask替換進(jìn)程的信號掩碼,并暫停進(jìn)程執(zhí)行,直到收到信號為止 sigsuspend返回后將恢復(fù)調(diào)用之前的信號掩碼 信號處理函數(shù)完成后,進(jìn)程將繼續(xù)執(zhí)行 該系統(tǒng)調(diào)用始終返回-1,并將errno設(shè)置為EINTRtask_struct中與信號處理相關(guān)的成員 struct signal_struct *signal 信號描述符結(jié)構(gòu),為每種信號選擇處理函數(shù) struct sighand_struct *sighand 包含信號處理函數(shù)描述符的數(shù)組,信號作為數(shù)組序號
57、 sigset_t blocked, real_blocked; 被阻塞信號的掩碼,每種信號類型對應(yīng)一個元素 struct sigpending pending; 維護(hù)本進(jìn)程中的未決信號 sigset_t saved_sigmask; 保存信號掩碼 定義TIF_RESTORE_SIGMASK時恢復(fù)信號掩碼62task_struct信號處理相關(guān)數(shù)據(jù)結(jié)構(gòu)關(guān)系圖6364System V IPC概述 IPC資源 表示單獨的消息隊列、共享內(nèi)存或信號量集合 具有相同類型的接口函數(shù) 信號量集合 實現(xiàn)進(jìn)程同步 消息隊列以異步方式為通信頻繁、但數(shù)據(jù)量少的進(jìn)程通信提供服務(wù) 共享主存為數(shù)據(jù)量大的進(jìn)程間通信提供服務(wù)
58、共同點 通過 System V IPC對象通信時,需傳遞該對象的唯一IPC標(biāo)識符 訪問System V IPC對象時必須經(jīng)過許可檢驗 System V IPC對象的訪問權(quán)限由對象創(chuàng)建者設(shè)置65IPC對象標(biāo)識符與IPC鍵 IPC標(biāo)識符 由內(nèi)核分配給IPC對象,在系統(tǒng)內(nèi)部唯一 IPC對象標(biāo)識符的獲?。篨XXget() 將IPC鍵傳遞給以sys_打頭的內(nèi)核函數(shù),并為用戶分配一個與IPC對象相對應(yīng)的數(shù)據(jù)結(jié)構(gòu) 返回一個32位IPC標(biāo)識符,進(jìn)程使用此標(biāo)識符對該資源進(jìn)行訪問 IPC鍵 IPC對象的外部表示,可由程序員選擇 如果鍵是公用的,則系統(tǒng)中所有進(jìn)程通過權(quán)限檢查后,均可找到和訪問相應(yīng)IPC對象 每個進(jìn)程
59、都可建立一個鍵值為IPC_PRIVATE的私有IPC對象66IPC鍵的創(chuàng)建 創(chuàng)建函數(shù) key_t ftok( char * filename, int id); 功能說明 將一個現(xiàn)存文件名(對應(yīng)文件必須是可訪問的)和一個整數(shù)標(biāo)識符id轉(zhuǎn)換成一個key_t值 在Linux系統(tǒng)中,調(diào)用該函數(shù)時,系統(tǒng)將該文件的索引節(jié)點號取出,并在前面加上子序號,從而得到key_t返回值IPC資源的全局定義v消息隊列 msgid_ds : 16個 定義位置:/proc/sys/kernel/msgmniv共享內(nèi)存 shmid_ds : 4096個 定義位置:/proc/sys/kernel/shmmniv信號量 se
60、mid_ds:128個 定義位置:/proc/sys/kernel/sem6768System V IPC的基本操作 操作函數(shù)(XXX代表msg、sem、shm三者之一) XXXget():獲得IPC標(biāo)識符 XXXctl():控制IPC資源 操作模式 先通過XXXget()創(chuàng)建一個IPC資源,返回IPC標(biāo)識符 隨后操作均以IPC資源標(biāo)識符為參數(shù),對相應(yīng)IPC資源進(jìn)行操作 其他進(jìn)程可通過XXXget()獲取已有的IPC資源標(biāo)識符(權(quán)限允許的話),并對其操作請求IPC標(biāo)識符時返回的錯誤碼69錯誤碼錯誤碼說明說明EACCESS進(jìn)程沒有適當(dāng)?shù)脑L問權(quán)限進(jìn)程沒有適當(dāng)?shù)脑L問權(quán)限EEXIST進(jìn)程試圖創(chuàng)建一個和已有關(guān)鍵字相同的進(jìn)程試圖創(chuàng)建一個和已有關(guān)鍵字相同的IPC資源資源EINVAL在在XXXget()函數(shù)中
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 充電樁設(shè)備選型與采購方案
- 2025年中級機(jī)修鉗工(助理技師)考試試卷:機(jī)械加工企業(yè)安全生產(chǎn)
- 油田廢氣與廢水處理方案
- 固廢處理工藝流程優(yōu)化方案
- 城市排澇工程環(huán)境影響評估方案
- 二零二五年產(chǎn)權(quán)式商鋪返租投資收益保障與管理合同
- 夜間施工安全管理與控制方案
- 2025版廠房租賃合同及租賃場地配套設(shè)施使用規(guī)定
- 二零二五年度可再生能源技術(shù)股份合作投資合同
- 噸(進(jìn)階)小學(xué)數(shù)學(xué)三年級上冊 人教新版同步分層作業(yè)(含解析)
- DB37-T4894-2025植物耐鹽性田間鑒定設(shè)施建設(shè)技術(shù)規(guī)程
- 循環(huán)系統(tǒng)管理課件
- 餐廳服務(wù)流程與接待標(biāo)準(zhǔn)
- 高一秋季開學(xué)第一課班會課件:金秋逐夢啟新程青春執(zhí)筆繪華章
- 多主體創(chuàng)新博弈-洞察及研究
- 嬰幼兒發(fā)育商測評師培訓(xùn)大綱
- 2025-2030中國氨基胍碳酸鹽行業(yè)產(chǎn)銷狀況及應(yīng)用前景預(yù)測報告
- 影刀RPA(競品)分析報告
- 威視數(shù)字化轉(zhuǎn)型的軌跡與成效研究
- 小學(xué)語文教師招聘考試試題(含答案)2025
- 醫(yī)院信息安全管理制度
評論
0/150
提交評論