文章目錄
- 1. 信號的產生
- 1.1 硬體產生
- 1.2 軟體產生
- 2. 信號的注冊
- 3. 信號的注銷
- 3.1 非可靠信號
- 3.2 可靠信號
- 4. 信號的處理方式
1. 信號的產生
1.1 硬體產生
ctrl + c:SIGINT(2)
ctrl + z:SIGTSTP(20)
ctrl + |:SIGQUIT(3)
??如何查看信號的資訊以及查看信號的默認處理動作?
man 7 signal
??作業系統對信號的處理動作:

??Term:終止
??Ign:忽略
??Core:終止+產生coredump檔案
??Stop:停止
??Cont:繼續
如果某一個信號的處理動作是“core”:
??1.默認是需要完成終止行程+產生coredump檔案
??2.產生coredump檔案,依賴ulimit -a==>“core file size”和磁盤大小
core file size 設定成為unlimited
信號具體的資訊:信號的名稱 + 信號的值(整數)+ action + 描述

1.2 軟體產生
kill命令:
??kill [pid]可以終止一個行程
??kill -[num] [pid] :給行程號為pid的行程發送一個信號值為num的信號
kill函式
??int kill(pid_t pid, int sig);
??功能:給pid行程發送sig信號
??給自己發信號
eg:kill (getpid(),9)
??int raise(int sig);
??功能:誰呼叫給誰發送sig信號
2. 信號的注冊
??1.一個行程收到一個信號,這個程序我們稱之為注冊,
??2.信號的注冊和信號的注銷并不是一個程序,是兩個獨立的程序,
??3.信號的注冊分為兩種情況,非可靠信號的注冊和可靠信號的注冊

??1.在作業系統內核“struct task_struct”結構體內部有一個變數:“struct sigpending pending”
??2.內核定義的結構體“struct sigpending”當中有兩個變數:一個是內核定義的雙向鏈表第二個是:sigset_t signal
??3.內核定義的型別“sigset_t”為一個結構體,在結構體內部有一個變數,該變數為一個陣列,是無符號長整型的陣列
??unsigned long sig[_NSIG_WORDS];
??1.信號的注冊本質上就是在使用sig陣列,但是并不是按照陣列型別的方式在使用,而是按照位圖(位元為)的方式在使用:
??eg:某一個信號注冊,則將某一個信號對應的位元位置為1
??2.sig陣列的位元位個數遠遠大于62,剩余的位元位為保留位
????struct sigpending ==> sigset_t signal ==> sig[xxx]
??一般在信號注冊的時候,稱之為操作sig位圖(sig[xxx]),內核當中對于注冊的時候,還有一個sigqueue佇列,信號的注冊邏輯位,將信號對應的sig位圖當中的位元位置為1,并且在sigqueue佇列當中添加一個sigqueue節點;通過注冊第一個信號兩次,來區分可靠信號和非可靠信號的注冊邏輯,
非可靠信號的注冊:
第一次:
??1.更改信號對應在sig位圖當中的位元位(0–1)
??2.在sigqueue佇列當中添加sigqueue節點
第二次:
??1.更改信號對應的sig位圖當中的位元位(1–1)
??2.對于第二次的信號,不添加sigqueue節點到sigqueue佇列當中
注意:
??如果有多個同一個信號來注冊,那么對于非可靠信號而言,只會添加一次sigqueue節點,換言之,只注冊了一次,
可靠信號的注冊:
第一次:
??1.更改信號對應在sig位圖當中的位元位(0–1)
??2.在sigqueue佇列當中添加sigqueue節點
第二次:
??1.更改sig位圖(1–1)
??2.在sigqueue佇列當中添加sigqueue節點
注意:
??如果有多次同一個可靠信號來注冊,那么對于可靠信號而言,會添加多次sigqueue節點,換言之,會注冊多次
3. 信號的注銷
3.1 非可靠信號
??1.將信號對應到sig位圖當中的位元位置為0
??2.將對應的非可靠信號的sigqueue節點進行出隊操作
3.2 可靠信號
??1.先將可靠信號對應的sigqueue進行出隊操作
??2.判斷sigqueue佇列當中是否有同類的可靠信號的sigqueue節點,如果有,不會將sig位圖當中對應的位元位置為0,如果沒有,將sig位圖當中對應的位元位置為0

4. 信號的處理方式
默認處理方式: 在作業系統內核當中定義好了
??宏:SIG_DFL
忽略處理方式: 作業系統定義行程收到某一個信號之后,忽略掉(行程即使收到了某個信號,行程也不會做任何事情)
??宏:SIG_IGN
??eg:僵尸行程:子行程先于父行程退出,子行程會向父行程發送SIGCHLD信號,父行程對SIGCHLD信號是忽略處理的,所以父行程并不會做任何事情,導致子行程的資源沒有行程進行回收,從而子行程變成僵尸行程
自定義處理方式:
??1.程式員可以定義某一個信號的處理方式
??2.函式
??typedef void (*sighandler_t)(int);
??sighandler_t signal(int signum,sighandler_t handler);
??signum:待要更改的信號的值
??handler:函式指標,接收一個函式的地址,這個函式沒有回傳值,有一個int型別的引數自定義signum這個信號的處理方式,定義為handler這個函式指標保存的函式地址對應的函式,換句話說,當行程收到signum這個信號的時候,就會呼叫handler當中保存的函式,
代碼

現象

??1.signal函式向內核注冊了一個信號的處理函式,呼叫signal函式的時候,并沒有呼叫注冊的函式(注冊的函式在行程收到行程之后才呼叫),這種方式稱之為“回呼”,
??int sigaction(int signum, const struct sigaction *act, struct sigaction * oldact);
??signum:待要自定義處理的信號
??act:要將信號處理方式更改為act
??oldact:原來的處理方式
struct sigaction
{
void (*sa_hander)(int);//保存信號默認函式處理方式的函式指標
void (*sa_sigaction)(int, siginfo_t * , void *);//函式指標,但是這個函式指標需要配合sa_flags一起使用,當sa_flags當中的值為SA_SIGINFO的時候,信號處理是按照“sa_sigaction”當中保存的函式地址來處理的
sigset_t sa_mask;//當行程在處理某一個信號的時候,有可能還會收到其他的信號,此時,其他的信號就暫時存在sa_mask當中,
int sa_flags;
void (*sa_restorer)(void);//保留欄位
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280297.html
標籤:其他
