Linux應用 之 訊號

2021-10-05 16:05:05 字數 4386 閱讀 2965

1.  訊號可以理解為軟體中斷,是在軟體層次上對中斷機制的一種模擬,在原理上,乙個程序收到乙個訊號與處理器收到乙個中斷請求可以說是差不多的。

2. 訊號機制的根本是每個程序都維護著一張訊號表,通過訊號表的操作。訊號是用位圖存的,只有乙個bit。

3. 訊號的**需要經過核心控制,這是為了安全考慮。

3.1. 訊號是如何產生的呢?有三種,第一種是訪問非法記憶體啊,哎這時候產生乙個訊號(中斷),第二種是使用者按ctrl+z的時候,哎,這時候會終止程序是吧,這就是乙個訊號,第三種就是自己使用kill函式,綜上所述,訊號的實質就是中斷。

4. 訊號是程序間通訊機制中唯一的非同步通訊機制,乙個程序不必通過任何操作來等待訊號的到達。

5. 收到訊號的程序三種處理方法,其實訊號就像中斷,要麼不理它,要麼就用中斷函承接,要麼就用預設方法處理。程序收到乙個訊號後,會檢查對該訊號的處理機制。如果是sig_ign,就忽略該訊號;如果是sig_dft,則會採用系統預設的處理動作,通常是終止程序或忽略該訊號;如果給該訊號指定了乙個處理函式(捕捉),則會中斷當前程序正在執行的任務,轉而去執行該訊號的處理函式,返回後再繼續執行被中斷的任務。

6. 一開始的訊號比較簡單(0~31),會丟失,後來新添了一些訊號,這些訊號就不會丟失了,這就是不可靠訊號與可靠訊號的**。訊號值小於sigrtmin的訊號都是不可靠訊號。訊號值位於sigrtmin和sigrtmax之間的訊號都是可靠訊號。訊號的可靠與不可靠只與訊號值有關,與訊號的傳送及安裝函式無關。目前linux中的signal()是通過sigation()函式實現的,因此,即使通過signal()安裝的訊號,在訊號處理函式的結尾也不必再呼叫一次訊號安裝函式。同時,由signal()安裝的實時訊號支援排隊,同樣不會丟失。這兩個函式的最大區別在於,經過sigaction安裝的訊號都能傳遞資訊給訊號處理函式,而經過signal安裝的訊號不能向訊號處理函式傳遞資訊。對於訊號傳送函式來說也是一樣的。

舉個例子:

訊號處理的大致流程如下:訊號產生 -> 訊號註冊 -> 訊號在程序中登出 -> 訊號處理函式執行完畢

更簡單的說,就是用signal註冊訊號函式即可,這對於說的是本身已存在的那幾十個訊號。而訊號用另一函式傳送時,用kill即可,kill(pid, 訊號值),sigaction()是poxis的

a程序傳送的訊號訊息,其實就是根據自己的訊號表,根據需要對相應的表項進行設定。核心接受到這個訊號訊息後,會先檢查a程序是否有許可權對b程序的訊號表對應的項進行設定,如果可以,就會對b程序的訊號表進行設定,這裡面訊號處理有個特點,就是沒有排隊的機制,也就是說某個訊號被設定之後,如果b程序還沒有來及進行響應,那麼如果後續第二個同樣的訊號訊息過來,就會被阻塞掉,也就是丟棄。

核心對b程序訊號設定完成後,就會傳送中斷請求給b程序,這樣b程序就進入到核心態,這個時候程序b根據那個訊號表,查詢對應的此訊號的處理函式,然後設定frame,設定好之後,跳回到使用者態執行訊號處理函式,處理完成後,再次返回到核心態,再次設定frame,然後再次返回使用者態,從中斷位置開始繼續執行。

這個frame其實就是在使用者態和核心態之間跳轉的時候,對堆疊現場的壓棧儲存。

第9號只是其中的一種。兩個常用的訊號:sigterm和sigkill,第乙個僅僅是比較友好。

linux支援的訊號列表如下。很多訊號是與機器的體系結構相關的

訊號值 預設處理動作 發出訊號的原因

sighup 1 a 終端掛起或者控制程序終止

sigint 2 a 鍵盤中斷(如break鍵被按下)

sigquit 3 c 鍵盤的退出鍵被按下

sigill 4 c 非法指令

sigabrt 6 c 由abort(3)發出的退出指令

sigfpe 8 c 浮點異常

sigkill 9 aef kill訊號

sigse** 11 c 無效的記憶體引用

sigpipe 13 a 管道破裂: 寫乙個沒有讀埠的管道

sigalrm 14 a 由alarm(2)發出的訊號

sigterm 15 a 終止訊號

sigusr1 30,10,16 a 使用者自定義訊號1,這兩個是自己用的,蠻重要的,就是用這兩個。

sigusr2 31,12,17 a 使用者自定義訊號2

sigchld 20,17,18 b 子程序結束訊號

sigcont 19,18,25 程序繼續(曾被停止的程序)

sigstop 17,19,23 def 終止程序

sigtstp 18,20,24 d 控制終端(tty)上按下停止鍵

sigttin 21,21,26 d 後台程序企圖從控制終端讀

sigttou 22,22,27 d 後台程序企圖從控制終端寫

1~31號為普通訊號,34~36號訊號為實時訊號。

實時訊號(real-time signal):編號為34~46,它們通常與普通訊號有很大的不同,因為他們必須排序以便傳送多個訊號能被接收到。但是同種訊號的普通訊號並不排序,儘管在linux核心並不使用實時訊號,它還是通過幾個特定的系統呼叫完全實現了posix標準。實時訊號就是可靠訊號?

處理動作一項中的字母含義如下

因此為什麼說傳送訊號函式叫kill,原因就是預設操作都是關閉吧。

早期unix系統只定義了32種訊號,前32種訊號已經有了預定義值,每個訊號有了確定的用途及含義,並且每種訊號都有各自的預設動作。如按鍵盤的ctrl ^c時,會產生sigint訊號,對該訊號的預設反應就是程序終止。後32個訊號表示實時訊號,等同於前面闡述的可靠訊號。這保證了傳送的多個實時訊號都被接收。

非實時訊號都不支援排隊,都是不可靠訊號;實時訊號都支援排隊,都是可靠訊號。

好了接下來說函式,

typedef void (*sighandler_t) (int)

sighandler_t signal(int signum, sighandler_t handler);

返回原訊號處理函式,或sig_err,什麼叫返回原處理訊號函式呢,就是你只是想鉤子一下,其他的仍然super處理,哎,那麼就有用了。

signal()是最簡單的給程序安裝訊號處理器的函式,第乙個引數指定訊號,第二個引數為該訊號指定乙個處理函式。

程式被注入訊號後,什麼時候會處理呢?在從核心態返回到使用者態的時候處理。但是程式設計就簡單多了,就像中斷一樣,或者監聽一樣就行。

kill命令是呼叫 kill 函式實現的, kill 函式可以給乙個特定的程序傳送指定的訊號;

raise函式可以給當前程序傳送指定的訊號(自己也可以給自己傳送訊號),原型如下:

#include

int kill(pid_t pid, int signum); //給任意程序傳送任意訊號

int raise(int signo); //給自己傳送任意訊號

兩者都是成功返回0,失敗返回-1

例如,定時器就是借助訊號實現的。

#include

unsigned int alarm(unsigned int seconds);

引數seconds:alarm函式安排核心在seconds秒內傳送乙個sigalrm訊號給呼叫程序,如果soconds等於0,那麼不會排程新的鬧鐘(alarm),也就是說,alarm本身並不是迴圈計時器,它只傳送一次而已。

返回值:前一次鬧鐘剩餘的秒數,若以前沒有設定鬧鐘,則為0

用的是sigalrm訊號,詳細見示例。

每日乙個小常識:

& 放在命令後面表示設定此程序為後台程序

預設情況下,程序是前台程序,這時此程序(命令執行相當於本質是開啟乙個程序)就把shell給佔據了,我們無法進行其他操作,對於那些沒有互動的程序,很多時候,我們希望將其在後台啟動,可以在啟動引數的時候加乙個'&'實現這個目的。

通常會返回乙個pid,然後這個shell就可以隨便使用了。

shell可以同時執行乙個前台程序和任意多個後台程序,只有前台程序才能接受諸如ctrl+c這樣的訊號。

ctrl + c 和ctrl + z都是中斷命令,但是他們的作用卻不一樣.

ctrl + c 是強制中斷程式的執行,程序已經終止。 ctrl + c 傳送 sigint訊號 

ctrl + z 的是將任務掛起(暫停的意思),但是此任務並沒有結束,他仍然在程序中他只是維持掛起的狀態,使用者可以使用fg/bg操作繼續前台或後台的任務,fg命令重新啟動前台被中斷的任務,bg命令把被中斷的任務放在後台執行. 

例如:當你vi乙個檔案是,如果需要用shell執行別的操作,但是你又不打算關閉vi,因為你得存檔推出,你可以簡單的按下ctrl+z,shell會將vi程序掛起~,當你結束了那個shell操作之後,你可以用fg命令繼續vi你的檔案。

ctrl + d 不是傳送訊號,而是表示乙個特殊的二進位制值,表示 eof。在shell中,ctrl-d表示推出當前shell.   就是你想關閉當前shell,簡單ctrl+d就行,否則用ctrl+c,就別用ctrl+z了,當然,用shell開啟的程式只能依附於該shell,如果該shell關閉了,那麼開啟的程式自然也就都關閉了。

linux應用之 程序通訊

程序間通訊基礎 程序間通訊的英文縮寫 ipc 為什麼需要程序間通訊?資料傳輸,資源共享,通知事件,程序控制等。linux程序間通訊方式 6種 管道,訊號,訊息佇列,共享記憶體,訊號量,套接字。各種程序間通訊方式詳解 1 管道通訊 int pipe int name 2 1 成功返回0 失敗返回 1 ...

Linux 多執行緒應用 訊號產生,訊號處理

筆者有一種應用場景,a 執行緒從 socket 接收指令,根據指令在 b 執行緒進行相應工作。採用訊號機制,設定 sigusr1 的訊號處理函式 sighandler,a 執行緒解析指令後發射訊號 sigusr1,b 執行緒執行sighandler.因對 posix 訊號機制不熟,過程中產生了一些誤...

Linux拓展應用之重定向程式設計

使用dup 及dup2函式可以實現linux的標準輸入輸出重定向功能。原理很簡單,即關閉標準的輸入輸出裝置 0 1 2 開啟或複製某普通檔案,並使其檔案描述符為0 1 2。dup 及dup2 函式宣告如下 from usr include unistd.h int dup int fd int du...