Linux環境程序間通訊

2023-01-01 18:51:04 字數 4977 閱讀 2204

在訊號(上)中,討論了linux訊號種類、**、如何安裝乙個訊號以及對訊號集的操作。本部分則首先討論從訊號的生命週期上認識訊號,或者巨集觀上看似簡單的訊號機制(程序收到訊號後,作相應的處理,看上去再簡單不過了),在微觀上究竟是如何實現的,也是在更深層次上理解訊號。接下來還討論了訊號程式設計的一些注意事項,最後給出了訊號程式設計的一些例項。

一、訊號生命週期

從訊號傳送到訊號處理函式的執行完畢

對於乙個完整的訊號生命週期(從訊號傳送到相應的處理函式執行完畢)來說,可以分為三個重要的階段,這三個階段由四個重要事件來刻畫:訊號誕生;訊號在程序中註冊完畢;訊號在程序中的登出完畢;訊號處理函式執行完畢。相鄰兩個事件的時間間隔構成訊號生命週期的乙個階段。

下面闡述四個事件的實際意義:

1. 訊號"誕生"。訊號的誕生指的是觸發訊號的事件發生(如檢測到硬體異常、定時器超時以及呼叫訊號傳送函式kill()或sigqueue()等)。

2. 訊號在目標程序中"註冊";程序的task_struct結構中有關於本程序中未決訊號的資料成員:

3. struct sigpending pending:

4. struct sigpending;

第三個成員是程序中所有未決訊號集,第

一、第二個成員分別指向乙個sigqueue型別的結構鏈(稱之為"未決訊號資訊鏈")的首尾,資訊鏈中的每個sigqueue結構刻畫乙個特定訊號所攜帶的資訊,並指向下乙個sigqueue結構:

struct sigqueue

訊號在程序中註冊指的就是訊號值加入到程序的未決訊號集中(sigpending結構的第二個成員sigset_t signal),並且訊號所攜帶的資訊被保留到未決訊號資訊鏈的某個sigqueue結構中。只要訊號在程序的未決訊號集中,表明程序已經知道這些訊號的存在,但還沒來得及處理,或者該訊號被程序阻塞。

注:當乙個實時訊號傳送給乙個程序時,不管該訊號是否已經在程序中註冊,都會被再註冊一次,因此,訊號不會丟失,因此,實時訊號又叫做"可靠訊號"。這意味著同乙個實時訊號可以在同乙個程序的未決訊號資訊鏈中占有多個sigqueue結構(程序每收到乙個實時訊號,都會為它分配乙個結構來登記該訊號資訊,並把該結構新增在未決訊號鏈尾,即所有誕生的實時訊號都會在目標程序中註冊);

當乙個非實時訊號傳送給乙個程序時,如果該訊號已經在程序中註冊,則該訊號將被丟棄,造成訊號丟失。因此,非實時訊號又叫做"不可靠訊號"。這意味著同乙個非實時訊號在程序的未決訊號資訊鏈中,至多占有乙個sigqueue結構(乙個非實時訊號誕生後,(1)、如果發現相同的訊號已經在目標結構中註冊,則不再註冊,對於程序來說,相當於不知道本次訊號發生,訊號丟失;(2)、如果程序的未決訊號中沒有相同訊號,則在程序中註冊自己)。

8. 訊號在程序中的登出。在目標程序執行過程中,會檢測是否有訊號等待處理(每次從系統空間返回到使用者空間時都做這樣的檢查)。

如果存在未決訊號等待處理且該訊號沒有被程序阻塞,則在執行相應的訊號處理函式前,程序會把訊號在未決訊號鏈中占有的結構卸掉。是否將訊號從程序未決訊號集中刪除對於實時與非實時訊號是不同的。對於非實時訊號來說,由於在未決訊號資訊鏈中最多隻占用乙個sigqueue結構,因此該結構被釋放後,應該把訊號在程序未決訊號集中刪除(訊號登出完畢);而對於實時訊號來說,可能在未決訊號資訊鏈中占用多個sigqueue結構,因此應該針對占用sigqueue結構的數目區別對待:

如果只占用乙個sigqueue結構(程序只收到該訊號一次),則應該把訊號在程序的未決訊號集中刪除(訊號登出完畢)。否則,不應該在程序的未決訊號集中刪除該訊號(訊號登出完畢)。

程序在執行訊號相應處理函式之前,首先要把訊號在程序中登出。

9. 訊號生命終止。程序登出訊號後,立即執行相應的訊號處理函式,執行完畢後,訊號的本次傳送對程序的影響徹底結束。

注:1)訊號註冊與否,與傳送訊號的函式(如kill()或sigqueue()等)以及訊號安裝函式(signal()及sigaction())無關,只與訊號值有關(訊號值小於sigrtmin的訊號最多隻註冊一次,訊號值在sigrtmin及sigrtmax之間的訊號,只要被程序接收到就被註冊)。

2)在訊號被登出到相應的訊號處理函式執行完畢這段時間內,如果程序又收到同一訊號多次,則對實時訊號來說,每一次都會在程序中註冊;而對於非實時訊號來說,無論收到多少次訊號,都會視為只收到乙個訊號,只在程序中註冊一次。

二、訊號程式設計注意事項

1. 防止不該丟失的訊號丟失。如果對八中所提到的訊號生命週期理解深刻的話,很容易知道訊號會不會丟失,以及在**丟失。

2. 程式的可移植性

考慮到程式的可移植性,應該盡量採用posix訊號函式,posix訊號函式主要分為兩類:

o posix 1003.1訊號函式: kill()、sigaction()、sigaddset()、sigdelset()、sigemptyset()、sigfillset()、sigismember()、sigpending()、sigprocmask()、sigsuspend()。

o posix 1003.1b訊號函式。posix 1003.

1b在訊號的實時性方面對posix 1003.1做了擴充套件,包括以下三個函式: sigqueue()、sigtimedwait()、sigwaitinfo()。

其中,sigqueue主要針對訊號傳送,而sigtimedwait及sigwaitinfo()主要用於取代sigsuspend()函式,後面有相應例項。

o #include <>

o int sigwaitinfo(sigset_t *set, siginfo_t *info).

該函式與sigsuspend()類似,阻塞乙個程序直到特定訊號發生,但訊號到來時不執行訊號處理函式,而是返回訊號值。因此為了避免執行相應的訊號處理函式,必須在呼叫該函式前,使程序遮蔽掉set指向的訊號,因此呼叫該函式的典型**是:

sigset_t newmask;

int rcvd_sig;

siginfo_t info;

sigemptyset(&newmask);

sigaddset(&newmask, sigrtmin);

sigprocmask(sig_block, &newmask, null);

rcvd_sig = sigwaitinfo(&newmask, &info)

if (rcvd_sig == -1)

呼叫成功返回訊號值,否則返回-1。sigtimedwait()功能相似,只不過增加了乙個程序等待的時間。

3. 程式的穩定性。

為了增強程式的穩定性,在訊號處理函式中應使用可重入函式。

訊號處理程式中應當使用可再入(可重入)函式(注:所謂可重入函式是指乙個可以被多個任務呼叫的過程,任務在呼叫時不必擔心資料是否會出錯)。因為程序在收到訊號後,就將跳轉到訊號處理函式去接著執行。

如果訊號處理函式中使用了不可重入函式,那麼訊號處理函式可能會修改原來程序中不應該被修改的資料,這樣程序從訊號處理函式中返回接著執行時,可能會出現不可預料的後果。不可再入函式在訊號處理函式中被視為不安全函式。

滿足下列條件的函式多數是不可再入的:(1)使用靜態的資料結構,如getlogin(),gmtime(),getgrgid(),getgrnam(),getpwuid()以及getpwnam()等等;(2)函式實現時,呼叫了malloc()或者free()函式;(3)實現時使用了標準i/o函式的。the open group視下列函式為可再入的:

_exit()、access()、alarm()、cfgetispeed()、cfgetospeed()、cfsetispeed()、cfsetospeed()、chdir()、chmod()、chown()、close()、creat()、dup()、dup2()、execle()、execve()、fcntl()、fork()、fpathconf()、fstat()、fsync()、getegid()、 geteuid()、getgid()、getgroups()、getpgrp()、getpid()、getppid()、getuid()、kill()、link()、lseek()、mkdir()、mkfifo()、 open()、pathconf()、pause()、pipe()、raise()、read()、rename()、rmdir()、setgid()、setpgid()、setsid()、setuid()、 sigaction()、sigaddset()、sigdelset()、sigemptyset()、sigfillset()、sigismember()、signal()、sigpending()、sigprocmask()、sigsuspend()、sleep()、stat()、sysconf()、tcdrain()、tcflow()、tcflush()、tcgetattr()、tcgetpgrp()、tcsendbreak()、tcsetattr()、tcsetpgrp()、time()、times()、 umask()、uname()、unlink()、utime()、wait()、waitpid()、write()。

即使訊號處理函式使用的都是"安全函式",同樣要注意進入處理函式時,首先要儲存errno的值,結束時,再恢復原值。因為,訊號處理過程中,errno值隨時可能被改變。另外,longjmp()以及siglongjmp()沒有被列為可再入函式,因為不能保證緊接著兩個函式的其它呼叫是安全的。

三、深入淺出:訊號應用例項

linux下的訊號應用並沒有想象的那麼恐怖,程式設計師所要做的最多只有三件事情:

1. 安裝訊號(推薦使用sigaction());

2. 實現三引數訊號處理函式,handler(int signal,struct siginfo *info, void *);

3. 傳送訊號,推薦使用sigqueue()。

實際上,對有些訊號來說,只要安裝訊號就足夠了(訊號處理方式採用預設或忽略)。其他可能要做的無非是與訊號集相關的幾種操作。

例項一:訊號傳送及處理

實現乙個訊號接收程式sigreceive(其中訊號安裝由sigaction())。

#include <>

#include

#include <>

void new_op(int,siginfo_t*,void*);

int main(int argc,char**ar**)

while(1)

}void new_op(int signum,siginfo_t *info,void *myact)

程序間通訊 linux

程序間通訊 1,使用共享記憶體 共享記憶體允許兩個或更多程序共享一給定的儲存區。因為資料不需要在各個程序之間複製,所以這是最快的一種程序間通訊方式。通過mmap 可以將檔案對映到不同的程序空間中,將他們作為多個程序共享的記憶體實現程序間通訊。利用mmap 進行程序間的資訊互動是無格式的,可以自己定義...

程序間通訊方法比較

win32應用程式中程序間通訊方法分析與比較 1 程序與程序通訊 程序是裝入記憶體並準備執行的程式,每個程序都有私有的虛擬位址空間,由 資料以及它可利用的系統資源 如檔案 管道等 組成。多程序 多執行緒是windows作業系統的乙個基本特徵。microsoft win32應用程式設計介面 appli...

Linux中的守護程序cron程序

439小遊戲 剛開始的時候對於後台程序,守護程序,以及cron程序的關係根本沒弄清楚,現在了解了。就像我前面的文字裡面寫的 後台程序 執行時無須使用者輸入的程式。可以在諸如 unix linux 之類的多工作業系統上執行多個後台程序,而使用者則與前台程序互動 例如,資料輸入 有些後台程序 例如守護程...