嵌入式Linux:信號(hào)是什么?
信號(hào)是Linux系統(tǒng)中用于通知進(jìn)程事件發(fā)生的一種機(jī)制,可以將其視為一種軟件中斷。
信號(hào)類似于硬件中斷,能夠打斷進(jìn)程當(dāng)前的執(zhí)行流程,從而實(shí)現(xiàn)對(duì)中斷機(jī)制的一種軟件層面的模擬。信號(hào)的主要作用是處理異步事件,因?yàn)榇蠖鄶?shù)情況下,信號(hào)的到達(dá)時(shí)間是不可預(yù)測(cè)的。
信號(hào)的一個(gè)主要目的是用于進(jìn)程間的通信。具有合適權(quán)限的進(jìn)程可以向另一個(gè)進(jìn)程發(fā)送信號(hào),這種用法不僅可以用作一種同步技術(shù),還可以視為進(jìn)程間通信(IPC)的最基礎(chǔ)形式。
1
信號(hào)的來源
信號(hào)可以由多種情況觸發(fā),以下是常見的幾種信號(hào)來源:
硬件異常
硬件檢測(cè)到錯(cuò)誤條件并通知內(nèi)核,內(nèi)核隨即發(fā)送相應(yīng)的信號(hào)給相關(guān)進(jìn)程。例如,當(dāng)執(zhí)行除數(shù)為零、訪問越界的內(nèi)存等異常操作時(shí),硬件會(huì)捕捉到這些錯(cuò)誤并通知內(nèi)核,內(nèi)核則向相關(guān)進(jìn)程發(fā)送信號(hào),如SIGFPE(浮點(diǎn)異常)或SIGSEGV(非法內(nèi)存訪問)。
終端輸入特殊字符
用戶通過終端輸入特定的控制字符可以產(chǎn)生信號(hào)。例如,按下CTRL + C組合鍵會(huì)產(chǎn)生SIGINT(中斷信號(hào)),可以終止前臺(tái)運(yùn)行的進(jìn)程;按下CTRL + Z會(huì)產(chǎn)生SIGTSTP(暫停信號(hào)),可暫停當(dāng)前前臺(tái)運(yùn)行的進(jìn)程。
進(jìn)程調(diào)用系統(tǒng)調(diào)用
進(jìn)程可以通過kill()系統(tǒng)調(diào)用向另一個(gè)進(jìn)程或進(jìn)程組發(fā)送信號(hào)。為了確保系統(tǒng)安全,發(fā)送信號(hào)的進(jìn)程和接收信號(hào)的進(jìn)程通常需要具有相同的所有者,或者發(fā)送信號(hào)的進(jìn)程的所有者是root超級(jí)用戶。
用戶命令
用戶可以通過kill命令向其它進(jìn)程發(fā)送信號(hào)。雖然kill命令的名稱聽起來像是用來“殺死”進(jìn)程,但實(shí)際上它可以發(fā)送任意信號(hào)。例如,kill -9 PID會(huì)向進(jìn)程發(fā)送SIGKILL信號(hào),強(qiáng)制終止指定進(jìn)程。
軟件事件
軟件檢測(cè)到特定條件發(fā)生時(shí)也會(huì)產(chǎn)生信號(hào)。這些條件可能包括:進(jìn)程設(shè)置的定時(shí)器到期、進(jìn)程使用的CPU時(shí)間超限、子進(jìn)程退出等。這些信號(hào)通常由內(nèi)核觸發(fā)并發(fā)送給相關(guān)進(jìn)程。
2
信號(hào)的處理方式
當(dāng)信號(hào)到達(dá)進(jìn)程時(shí),進(jìn)程需要對(duì)該信號(hào)進(jìn)行處理。通常,進(jìn)程對(duì)信號(hào)的處理方式有以下幾種:
忽略信號(hào)
進(jìn)程可以選擇忽略某些信號(hào),使其不對(duì)進(jìn)程的執(zhí)行產(chǎn)生影響。然而,有兩種信號(hào)SIGKILL和SIGSTOP是無法被忽略的,因?yàn)樗鼈兲峁┝私K止或停止進(jìn)程的可靠方法。如果進(jìn)程忽略某些由硬件異常產(chǎn)生的信號(hào),其行為可能是未定義的。
捕獲信號(hào)
進(jìn)程可以捕獲并處理信號(hào),通過預(yù)先定義的信號(hào)處理函數(shù)來響應(yīng)特定的信號(hào)。為了實(shí)現(xiàn)這一點(diǎn),進(jìn)程需要通過signal()或sigaction()系統(tǒng)調(diào)用來注冊(cè)信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),該函數(shù)將被執(zhí)行以處理相應(yīng)的事件。
執(zhí)行系統(tǒng)默認(rèn)操作
如果進(jìn)程沒有捕獲信號(hào),系統(tǒng)會(huì)對(duì)信號(hào)進(jìn)行默認(rèn)處理。對(duì)于大多數(shù)信號(hào),系統(tǒng)默認(rèn)的處理方式是終止進(jìn)程。然而,也有些信號(hào)的默認(rèn)處理方式是忽略。
3
信號(hào)的異步性
信號(hào)是異步事件的經(jīng)典實(shí)例。信號(hào)的產(chǎn)生對(duì)進(jìn)程而言是隨機(jī)的,進(jìn)程無法預(yù)測(cè)信號(hào)到達(dá)的具體時(shí)間。這種異步性與硬件中斷非常相似。進(jìn)程無法通過簡(jiǎn)單的變量測(cè)試或系統(tǒng)調(diào)用判斷信號(hào)是否產(chǎn)生,只有當(dāng)信號(hào)實(shí)際發(fā)生時(shí),系統(tǒng)才會(huì)通知進(jìn)程,打斷當(dāng)前執(zhí)行流程,跳轉(zhuǎn)到信號(hào)處理函數(shù)去執(zhí)行相應(yīng)操作。
4
信號(hào)編號(hào)
在Linux系統(tǒng)中,信號(hào)本質(zhì)上是int類型的數(shù)字編號(hào),類似于硬件中斷所對(duì)應(yīng)的中斷號(hào)。內(nèi)核為每一個(gè)信號(hào)定義了一個(gè)唯一的整數(shù)編號(hào),這些編號(hào)從數(shù)字1開始依次展開。每個(gè)信號(hào)都有一個(gè)對(duì)應(yīng)的名字,這個(gè)名字實(shí)際上是一個(gè)宏,通常以SIGxxx的形式出現(xiàn),例如SIGINT、SIGKILL等。
信號(hào)的整數(shù)編號(hào)與其符號(hào)名之間是一一對(duì)應(yīng)的關(guān)系,但由于不同操作系統(tǒng)的實(shí)現(xiàn)可能存在差異,某些信號(hào)的實(shí)際編號(hào)在不同系統(tǒng)中可能會(huì)有所不同。為了提高程序的可移植性,在編寫代碼時(shí),開發(fā)者通常使用信號(hào)的符號(hào)名而不是直接使用編號(hào)。例如,在程序中使用SIGINT來表示中斷信號(hào),而不是直接使用數(shù)字2(在大多數(shù)系統(tǒng)中,SIGINT的編號(hào)為2)。
信號(hào)的定義可以在或頭文件中找到,這些文件中定義了所有標(biāo)準(zhǔn)信號(hào)的編號(hào)和名稱。
需要注意,信號(hào)編號(hào)從1開始,而編號(hào)為0的信號(hào)在標(biāo)準(zhǔn)定義中并不存在。
#define SIGHUP 1 /* 掛斷 (POSIX). */#define SIGINT 2 /* 中斷 (ANSI). */#define SIGQUIT 3 /* 退出 (POSIX). */#define SIGILL 4 /* 非法指令 (ANSI). */#define SIGTRAP 5 /* 跟蹤陷阱 (POSIX). */#define SIGABRT 6 /* 異常終止 (ANSI). */#define SIGIOT 6 /* IOT 陷阱 (4.2 BSD). */#define SIGBUS 7 /* 總線錯(cuò)誤 (4.2 BSD). */#define SIGFPE 8 /* 浮點(diǎn)異常 (ANSI). */#define SIGKILL 9 /* 終止,無法阻塞 (POSIX). */#define SIGUSR1 10 /* 用戶自定義信號(hào) 1 (POSIX). */#define SIGSEGV 11 /* 段錯(cuò)誤 (ANSI). */#define SIGUSR2 12 /* 用戶自定義信號(hào) 2 (POSIX). */#define SIGPIPE 13 /* 管道破裂 (POSIX). */#define SIGALRM 14 /* 鬧鐘信號(hào) (POSIX). */#define SIGTERM 15 /* 終止 (ANSI). */#define SIGSTKFLT 16 /* 棧錯(cuò)誤. */#define SIGCHLD 17 /* 子進(jìn)程狀態(tài)改變 (POSIX). */#define SIGCLD SIGCHLD /* 與 SIGCHLD 相同 (System V). */#define SIGCONT 18 /* 繼續(xù)執(zhí)行 (POSIX). */#define SIGSTOP 19 /* 停止,無法阻塞 (POSIX). */#define SIGTSTP 20 /* 終端停止信號(hào) (POSIX). */#define SIGTTIN 21 /* 后臺(tái)從終端讀取 (POSIX). */#define SIGTTOU 22 /* 后臺(tái)向終端寫入 (POSIX). */#define SIGURG 23 /* 套接字緊急情況 (4.2 BSD). */#define SIGXCPU 24 /* 超過 CPU 時(shí)間限制 (4.2 BSD). */#define SIGXFSZ 25 /* 超過文件大小限制 (4.2 BSD). */#define SIGVTALRM 26 /* 虛擬時(shí)鐘信號(hào) (4.2 BSD). */#define SIGPROF 27 /* 程序執(zhí)行時(shí)鐘信號(hào) (4.2 BSD). */#define SIGWINCH 28 /* 窗口大小改變 (4.3 BSD, Sun). */#define SIGPOLL SIGIO /* 可輪詢事件發(fā)生 (System V). */#define SIGIO 29 /* I/O 操作完成 (4.2 BSD). */#define SIGPWR 30 /* 電源故障重啟 (System V). */#define SIGSYS 31 /* 錯(cuò)誤的系統(tǒng)調(diào)用. */#define SIGUNUSED 31 /* 未使用的信號(hào). */
在 Linux 系統(tǒng)下使用"kill -l"命令可查看到所有信號(hào),如下所示:
在實(shí)際開發(fā)中,合理使用信號(hào)處理機(jī)制可以提高程序的健壯性和響應(yīng)速度。開發(fā)者需要根據(jù)應(yīng)用場(chǎng)景選擇合適的信號(hào)處理方式,比如在關(guān)鍵任務(wù)中確保某些信號(hào)能夠及時(shí)處理,或者在某些情況下忽略不重要的信號(hào)以避免不必要的中斷。
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。