進程間通信-軟中斷
內容
- 使用軟中段機制實現Linux進程間通信
機理說明
軟中斷信號(signal)是一種簡單且最基本的進程通信機制,它最大的特點是提供了一種簡單的處理異步事件的方法。例如,常見的用戶從鍵盤鍵入組合鍵 Ctrl+C 來中斷一個程序的運行,或者在兩個進程之間通過某個信號來通知發生了異步事件,或者向系統或進程報告突發的硬件故障,如非法指令、運算溢出等。更重要的是,用戶進程還可以向自己發送信號以中斷進程的執行,並自動轉入指定的軟中斷處理函數去執行用戶自行安排的處理內容,處
理完畢后再返回用戶進程繼續執行,從而為應用程序提供了由用戶自行處理隨機事件的通信機制。軟中斷信號實現 (signal implementation) 是操作系統用來通知進程有事情發生的一種機制。由於這種信號總是在進程處於運行狀態時才會去響應,故稱之為軟中斷信號。軟中斷信號的使用者是操作系統和源程序,操作系統事先將系統的中可以使用的軟件中斷信號進行集中編碼並定義相應含義后,提交用戶使用。用戶可以通過相應的軟件中斷序號或軟中斷名稱來使用軟中斷,二者在使用上是等效的。用戶只能在操作系統提供的軟件中斷序號范圍內使用軟件中斷信號,不能自己創建新的軟件中斷信號。如果用戶的應用程序之間有信號需要發送,則可以使用操作系統預留給用戶使用的用戶信號 SIGUSR1 或用戶信號 SIGUSR2。
序號 | 名稱 | 含義 |
---|---|---|
1 | SIGHUP | 掛起 |
2 | SIGINT | Ctrl+C |
3 | SIGQUIT | Ctrl+\ |
4 | SIGILL | 非法指令 |
5 | SIGTRAP | 自陷,跟蹤代碼執行 |
6 | SIGIOT | IOT指令 |
7 | SIGBUS | 總線錯 |
8 | SIGFPE | 浮點數例外 |
9 | SIGKILL | 終止進程 |
10 | SIGUSR1 | 用戶定義信號1 |
11 | SIGEGV | 段越界 |
12 | SIGUSR2 | 用戶定義信號2 |
13 | SIGPIPE | 向非法管道中寫數據 |
14 | SIGALARM | 鬧鍾警報 |
15 | SIGTERM | 軟件中止 |
16 | 。。。 | |
17 | SIGCHLD | 子進程死亡 |
18 | 。。。 |
Linux 的軟中斷信號在/usr/src/linux-2.4/include/asm/signal.h 中定義。
調用函數說明
預置一個軟信號
signal(sig , function)
參數說明:
sig系統給定的軟中斷中的序號或名稱(查表)
function與軟中斷信號關聯的函數名,捕捉到軟中斷信號后轉到該函數執行
發送一個軟信號
int kill(pid ,sig)
功能:向pid發送sig
參數說明:
pid表示一個或一組進程的標識號
pid值 | 含義 |
---|---|
>0 | 發送給特定的pid進程 |
=0 | 發送給同組的所有進程 |
=-1 | 發送給同用戶標識符的進程 |
sig軟中斷信號的序號或名稱
注意:只能是核心或超級用戶進程才能 kill 來向任意的其他進程發送軟中斷信號,而普
通用戶進程只能 kill 向同組或同用戶標識的進程發送軟中斷信號,而不能向任意的其他進程
發送軟中斷信號。
思路
先使用 signal() 系統調用函數進行預置。預置的目的是將某個軟中斷信號與某個可執行的處理函數進行關聯,當信號發出並被指定的進程接收后,系統就中斷接收該軟件中斷信號進程的執行,轉而執行與信號相關聯的函數,該函數執行完畢后再返回被中斷的進程繼續執行。
事實上,除了用戶定義信號 SIGUSR1 和 SIGUSR2 外,其他軟中斷信號都已經由操作系統預置了相應的處理函數,用戶進程如果對這些軟中斷信號進行了預置,則使該信號與新的函數進行關聯,當該軟中斷信號被接收時,轉而執行的不再是操作系統預置的處理函數,而是用戶對該軟中斷信號重新預置的處理函數。
對於同一個軟中斷信號,可以通過多個 signal() 系統調用分別與不同的處理函數進行關聯。系統在響應該軟中斷信號時,執行的是當前預置的處理函數(最近預置的),從而實現同一軟中斷信號在不同的情況下轉向不同的處理函數去執行。
實例
使用軟中斷實現父子進程間通信
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
int k;
void int_func(int sig) /*中斷處理函數*/
{
k=0;
}
main()
{
int p;
int shmid;
char *viraddr;
char buffer[BUFSIZ];
signal(SIGUSR1,int_func); /*預置信號對應的函數*/
k=1;
shmid=shmget(1234,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while((p=fork())==-1);
if(p==0)
{
while(k==1); /*等待父進程發軟中斷信號*/
printf("Your message is :\n%s",viraddr);
/*輸出共享存儲區內容*/
shmdt(viraddr); /*斷開共享存儲區*/
shmctl(shmid,IPC_RMID,0); /*撤銷共享存儲區*/
exit(0);
}
else
{
while(1)
{
puts("Enter some text:");
fgets(buffer,BUFSIZ,stdin); /*從stdin中讀入輸入內容*/
strcat(viraddr,buffer); /*追加到共享存儲區*/
if(strncmp(buffer,"end",3)==0)
break;
}
shmdt(viraddr); /*斷開共享存儲區*/
kill(p,SIGUSR1); /*發送一個中斷信號*/
exit(0);
}
}