1、基本概念
程序阻塞:
程序執行條件得不到滿足,就自動放棄CPU資源而進入休眠狀態,以等待條件滿足,當條件滿足時,系統就將控制權還給該程序進行未完成的操作
共享資源:
程序間協調使用的系統資源
鎖定:
當某個程序使用共享資源時,可能需要防止別的程序對該資源的使用。Linux提供一些方法保證共享資源被某個程序使用時,其他程序不能使用,就稱為共享資源的鎖定
2、訊號
訊號的作用是通知一個或多個程序非同步事件的發生,也可以用來處理某種嚴重的錯誤,可以從核心發往程序,也可以從一個程序發往另一個程序,
例如:使用者在後臺啟動了一個程式,現在想要終止此程序的執行,就可以使用Kill命令將SIGTERM訊號傳送給這個程序,SIGTERM將終止該程序的執行
例如:執行exit()時,就向子程序的父程序傳送SIGCHLD訊號(子程序結束訊號),若此時父程序在執行wait(),則父程序會被喚醒,若不是在執行wait(),則此父程序不會捕捉到SIGCHLD訊號,該訊號就不起作用,子程序進入過渡狀態(如果父程序忽略SIGCHLD,子程序就會結束而不會進入過渡狀態)
在大多數情況下,當程序收到一個訊號時,會被正常終止,相當於程序執行了一個臨時加入的exit()呼叫。
訊號SIGQUIT、SIGILL、SIGTRAP、SIGFPE會導致一個非正常終止,它們將發生核心轉貯,也就是把程序的記憶體映像寫入程序當前目錄的core檔案中,core檔案以二進位制形式記錄了終止時程式中全部變數值、硬體暫存器值和核心中的控制資訊,非正常終止程序的退出狀態除了其低端第7位置位外,其他與通過訊號正常終止時一樣
3、訊號的復位
當一個訊號的訊號處理函式執行時,該程序又收到了同樣的訊號,那麼該訊號將會被儲存而不會中斷訊號處理函式,直到訊號處理函式執行完後重新呼叫相應處理函式,但是如果接收到了其他型別的訊號,那麼該訊號處理函式將會被中斷
例如:
#include <signal.h>
int interrupt()
{
printf(“Interrupt called\n”);
sleep(3);
printf(“Interrupt Func Ended.\n”);
}
main()
{
signal(SIGINT,interrupt);
printf(“Interrupt set for SIGINT\n”);
sleep(10);
printf(“Program NORMAL ended.\n”);
return;
}
執行結果就是
Interrupt set for SIGINT
<ctrl+c>
Interrupt called
<ctrl+c>
Func Ended
Interrupt called
Func Ended
Program NORMAL ended.
而程式碼:
#include <signal.h>
int interrupt()
{
printf(“Interrupt called\n”);
sleep(3);
printf(“Interrupt Func Ended.\n”);
}
int catchquit()
{
printf(“Quit called\n”);
sleep(3);
printf(“Quit ended.\n”);
}
main()
{
signal(SIGINT,interrupt);
signal(SIGQUIT,catchquit);
printf(“Interrupt set for SIGINT\n”);
sleep(10);
printf(“Program NORMAL ended.\n”);
return;
}
執行的結果是
Interrupt set for SIGINT
<ctrl+c>
Interrupt called
<ctrl+\>
Quit called
Quit ended.
Interrupt Func Ended.
Program NORMAL ended.
還有就是同一種訊號不能累積,如:
Interrupt set for SIGINT
<ctrl+c>
Interrupt called
<ctrl+c><ctrl+c><ctrl+c>
Func Ended
Interrupt called
Func Ended
Program NORMAL ended.
如果兩個訊號同時產生,系統不保證程序接收的順序,因此,訊號處理的順序就不可控
4、程序間傳送訊號
一個程序可以通過signal()呼叫來處理其他程序傳送來的訊號,同時也可以通過kill(pid_t pid,int sig)來向其他程序傳送訊號。pid指定了訊號傳送的物件程序。可以是程序識別符號,也可以是以下的值
1)pid = 0, 則訊號被髮送到當前程序所在的程序組的所有程序
2)pid = -1, 則訊號按程序識別符號從高到低的順序傳送給全部的程序
3)pid < -1,則訊號被髮送給識別符號為pid 絕對值的程序組裡的所有程序
訊號傳送的限制:普通使用者程序只能向具有與其相同的使用者識別符號的程序傳送訊號,也就是說一個使用者的程序不能向另一個使用者的程序傳送訊號,只有root使用者的程序才能給任何程序傳送訊號。
由於Kill需要知道目標程序識別符號,所以一般在父子程序之間進行訊號傳送
舉個例子:兩個程序,通過傳送SIGUSER1實現同步,兩個程序都處於死迴圈中,接收對方訊號前,處於暫停等待中,也就是pause(),使得程式暫停一直到訊號達到,然後程序輸出資訊,並用kill傳送一個訊號給對方,若使用者按了中斷鍵,兩個程序終止
#include <signal.h>
int ntimes = 0;
main()
{
int pid,ppid;
int p_action(), c_action();
/* 設定父程序的SIGUSR1 */
signal(SIGUSR1,p_action);
switch(pid = fork())
{
case -1: /*fork 失敗*/
perror("synchro");
exit(1);
case 0: /*子程序模組*/
/* 設定子程序的SIGUSR1 */
signal(SIGUSR1,c_action);
/* 獲得父程序的識別符號 */
ppid = getppid();
for(;;)
{
sleep(1);
kill(ppid,SIGUSR1);
pause();
}
/*死迴圈*/
break;
default: /*父程序模組*/
for (;;)
{
pause();
sleep(1);
kill(pid,SIGUSR1);
}
/*死迴圈*/
}
}
int p_action()
{
printf("Patent caught signal #%d\n",++ntimes);
}
int c_action()
{
printf("Child caught signal #%d\n",++ntimes);
}
執行結果就是
Patent caught signal #1
Child caught signal #1
Patent caught signal #2
Child caught signal #2
Patent caught signal #3
Child caught signal #3
Patent caught signal #4
Child caught signal #4
<ctrl+c>