|
ocfbiu1ymyg64014084508.gif (60.41 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
ocfbiu1ymyg64014084508.gif
2024-9-1 11:37 上傳
1 D+ v4 w- N0 ^* N
點(diǎn)擊上方藍(lán)色字體,關(guān)注我們+ L9 n8 Q9 \/ R e3 r& q0 Z
在Linux系統(tǒng)中,當(dāng)進(jìn)程接收到信號(hào)后,可以通過(guò)設(shè)置信號(hào)處理方式來(lái)決定如何響應(yīng)信號(hào)。# _# h5 T5 p1 B( ^7 F3 M
* s Y5 h( Q- ^6 M0 I7 F* I
通常,信號(hào)的處理方式可以是以下三種之一:% E* m/ }) }8 r7 o) S0 t& w4 Z. y
忽略信號(hào):進(jìn)程對(duì)該信號(hào)不做任何處理,直接忽略。捕獲信號(hào):為該信號(hào)設(shè)置一個(gè)處理函數(shù),當(dāng)信號(hào)到達(dá)時(shí)執(zhí)行該函數(shù)。執(zhí)行系統(tǒng)默認(rèn)操作:采用系統(tǒng)預(yù)定義的信號(hào)處理方式。
; N. o j% J; P, A1 ~ w. b5 K+ N/ x- J8 [
本篇文章主要講解進(jìn)程如何處理信號(hào)。Linux 系統(tǒng)提供了兩個(gè)主要的函數(shù) signal() 和 sigaction() 用于設(shè)置信號(hào)的處理方式。* t/ f6 `1 h; Z( f+ P9 e
1. l4 o' a Z2 T) {5 Z k; @
signal()函數(shù)! D) `' X4 d0 A6 n6 C3 ^
signal()函數(shù)的原型如下:8 w; x c6 l0 h/ o& Y- r# `$ g7 F
: J( O: b$ c6 u$ p: `9 r1 j* u#include typedef void (*sig_t)(int); sig_t signal(int signum, sig_t handler);
" G3 R9 ?1 u9 I" W3 p! ?4 ^& F函數(shù)參數(shù)和含義:% A2 \( e4 ?/ a/ {
signum:指定需要進(jìn)行設(shè)置的信號(hào)。你可以使用信號(hào)的名稱(如SIGINT)或者其對(duì)應(yīng)的數(shù)字編號(hào)。不過(guò),建議使用信號(hào)名稱,因?yàn)檫@樣可讀性更強(qiáng)。handler:這是一個(gè)sig_t類型的函數(shù)指針,用于指向信號(hào)的處理函數(shù)。handler可以設(shè)置為以下幾種:
9 t$ J9 `6 O7 ~/ ]用戶自定義函數(shù):這是一個(gè)處理函數(shù),在接收到信號(hào)時(shí)會(huì)自動(dòng)調(diào)用這個(gè)函數(shù)。該函數(shù)的參數(shù)是一個(gè)int類型的值,表示觸發(fā)該函數(shù)的信號(hào)編號(hào)。通過(guò)這個(gè)參數(shù),你可以在一個(gè)函數(shù)中處理多個(gè)信號(hào)。SIG_IGN:表示忽略該信號(hào),進(jìn)程在接收到該信號(hào)時(shí)不會(huì)進(jìn)行任何處理。SIG_DFL:表示采用系統(tǒng)的默認(rèn)處理方式,系統(tǒng)會(huì)對(duì)信號(hào)進(jìn)行其預(yù)定義的操作。
5 N2 H6 i" q; M* Z) A2 _' q5 k/ o/ v Q/ v. O) \0 C
返回值:signal()函數(shù)的返回值是一個(gè)sig_t類型的函數(shù)指針。成功調(diào)用時(shí),返回指向之前信號(hào)處理函數(shù)的指針,這意味著你可以保存這個(gè)指針,以便在將來(lái)恢復(fù)原來(lái)的信號(hào)處理方式。如果調(diào)用失敗,則返回SIG_ERR,并設(shè)置errno以指示錯(cuò)誤原因。: i/ I# g$ g |& k I
" A* M8 |: G) W0 }, B; H% d
以下是一個(gè)簡(jiǎn)單的示例代碼,展示如何使用signal()函數(shù)來(lái)捕獲SIGINT信號(hào),并執(zhí)行自定義的信號(hào)處理函數(shù):
; w* Z& K9 c2 J) O$ p" O/ u) @5 u" ]0 I0 W' v
#include #include #include // 自定義信號(hào)處理函數(shù)void handle_signal(int signal) { printf("Caught signal %d1 {! m F3 Y6 ~* c# ^
", signal);} int main() { // 將 SIGINT 信號(hào)處理方式設(shè)置為自定義的 handle_signal 函數(shù) signal(SIGINT, handle_signal); // 無(wú)限循環(huán),等待信號(hào) while(1) { printf("Running...& j% v5 Q) C" W* Y, m. c
"); sleep(1); } return 0;}2 H! {1 v7 W3 c. `
在上述代碼中,當(dāng)用戶按下CTRL+C(觸發(fā)SIGINT信號(hào))時(shí),自定義的handle_signal()函數(shù)會(huì)被調(diào)用,并輸出捕獲的信號(hào)編號(hào)。程序會(huì)繼續(xù)運(yùn)行,而不會(huì)終止。如果要忽略SIGINT信號(hào),可以將signal(SIGINT, handle_signal);改為signal(SIGINT, SIG_IGN);。
5 N( N" _0 P2 P) N2
' K# J q" q8 J4 Y. K1 rsigaction() 函數(shù)
2 S$ X6 H2 z$ W/ O' rsigaction() 函數(shù)是 Linux 系統(tǒng)中用于設(shè)置信號(hào)處理方式的一個(gè)更強(qiáng)大且靈活的系統(tǒng)調(diào)用。與 signal() 函數(shù)相比,sigaction() 提供了更詳細(xì)的控制和更高的移植性,因此更推薦在實(shí)際開發(fā)中使用它。
4 F1 H$ H, [" r$ C( o, `( P" Y. @ n9 V0 i
sigaction() 函數(shù)原型如下:
3 i% ^3 j/ B$ a' Z3 {3 }; `- _/ X9 Z$ |
#include int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);4 o% T; V7 U- X: x* C
函數(shù)參數(shù):1 H$ }5 {% s4 d
signum:指定要設(shè)置處理方式的信號(hào)編號(hào)。可以為除 SIGKILL 和 SIGSTOP 以外的任何信號(hào)。act:指向 struct sigaction 結(jié)構(gòu)體的指針,用于指定信號(hào)的新的處理方式。如果 act 為 NULL,則不改變信號(hào)的處理方式。oldact:指向 struct sigaction 結(jié)構(gòu)體的指針,用于存儲(chǔ)信號(hào)先前的處理方式。如果不需要獲取原來(lái)的處理方式,可將其設(shè)置為 NULL。
% v+ ?. ]. `- j! b' k+ o# l
8 w" y' `& _3 j% K! u! d返回值:成功返回 0;失敗返回 -1,并設(shè)置 errno。
$ J1 u" a& q6 y: z
; s! i2 ^6 B+ {9 y0 h% g7 Istruct sigaction 結(jié)構(gòu)體用于描述信號(hào)的處理方式,定義如下:
: ]5 C2 a- _/ s" C* _% w7 f+ ]; H( ^( B. W& t
struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void);};# q a/ n% h" K* b
成員變量如下:0 u1 W! v8 k c5 M* a& L
sa_handler:信號(hào)處理函數(shù)指針,與 signal() 函數(shù)中的 handler 參數(shù)相同。可設(shè)置為自定義函數(shù)、SIG_IGN(忽略信號(hào))或 SIG_DFL(系統(tǒng)默認(rèn)處理)。sa_sigaction:另一個(gè)信號(hào)處理函數(shù)指針,用于處理帶有更多信息的信號(hào)。與 sa_handler 互斥,通常使用 sa_handler。選擇使用 sa_sigaction 需設(shè)置 SA_SIGINFO 標(biāo)志。sa_mask:定義在執(zhí)行信號(hào)處理函數(shù)期間要阻塞的信號(hào)集合,以避免信號(hào)之間的競(jìng)爭(zhēng)條件。sa_flags:標(biāo)志位,用于控制信號(hào)的處理行為。常用標(biāo)志包括:# R+ `, I4 |0 W9 l) i) d
SA_NOCLDSTOP:阻止當(dāng)子進(jìn)程停止或恢復(fù)時(shí)發(fā)送 SIGCHLD 信號(hào)。SA_NOCLDWAIT:子進(jìn)程終止時(shí)不變?yōu)榻┦M(jìn)程。SA_NODEFER:不阻塞自身的信號(hào)。SA_RESETHAND:執(zhí)行完信號(hào)處理后將信號(hào)恢復(fù)為默認(rèn)處理方式。SA_RESTART:被信號(hào)中斷的系統(tǒng)調(diào)用在信號(hào)處理完成后重新發(fā)起。SA_SIGINFO:使用 sa_sigaction 代替 sa_handler。
# D% Q* K" }" c- L: j$ qsa_restorer:已過(guò)時(shí),通常不使用。
1 U3 @& o7 z: [: [/ ?- H' E
8 b; R# r/ W+ ^siginfo_t 結(jié)構(gòu)體用于在 sa_sigaction 處理信號(hào)時(shí)傳遞更多的上下文信息,結(jié)構(gòu)體定義如下:
5 ?5 {$ @, H9 Z: {$ O& q3 ^. }
" C2 V" [0 ]& _/ Etypedef struct siginfo { int si_signo; /* Signal number */ int si_errno; /* An errno value */ int si_code; /* Signal code */ pid_t si_pid; /* Sending process ID */ uid_t si_uid; /* Real user ID of sending process */ void *si_addr; /* Memory location which caused fault */ int si_status; /* Exit value or signal */ int si_band; /* Band event */ // ... 其他成員} siginfo_t;
* ^5 J; B( P$ o# t$ {4 f# G5 M" G下面是一個(gè)使用 sigaction() 捕獲 SIGINT 信號(hào)的示例代碼:
& }0 E: ~+ u8 k# y: }) D$ W
7 a7 c$ V( E, E" U1 J; Z8 {* _#include #include #include void handle_signal(int signal, siginfo_t *info, void *ucontext) { printf("Caught signal %d
' Z, R+ ]4 f- d", signal); printf("Signal sent by process %d
. @ A2 t+ \4 S) y- n6 ?", info->si_pid);} int main() { struct sigaction act; act.sa_sigaction = handle_signal; act.sa_flags = SA_SIGINFO; // 使用 sa_sigaction 而不是 sa_handler sigemptyset(&act.sa_mask); sigaction(SIGINT, &act, NULL); // 無(wú)限循環(huán),等待信號(hào) while(1) { printf("Running...
8 `: ?7 H( F5 ]0 a8 f# M"); sleep(1); } return 0;}
2 }: _% s+ p: M: ]2 z. I在這段代碼中,sigaction() 用來(lái)設(shè)置 SIGINT 信號(hào)的處理方式。當(dāng)用戶按下 CTRL+C 發(fā)送 SIGINT 信號(hào)時(shí),程序會(huì)調(diào)用 handle_signal() 函數(shù),該函數(shù)可以通過(guò) siginfo_t 結(jié)構(gòu)體獲取信號(hào)的更多信息,比如發(fā)送信號(hào)的進(jìn)程 ID。
$ m* m6 e3 v5 n4 q/ W+ s3
/ J; J3 o. W* r8 o2 m$ u1 M1 H注意事項(xiàng)
/ l7 |8 l% W% z* a. B當(dāng)一個(gè)應(yīng)用程序剛啟動(dòng)時(shí),或在程序中未調(diào)用 signal() 或 sigaction() 來(lái)顯式設(shè)置信號(hào)處理方式時(shí),進(jìn)程對(duì)所有信號(hào)的處理方式通常為系統(tǒng)默認(rèn)操作。這意味著大多數(shù)信號(hào)在未被特殊處理的情況下,都會(huì)執(zhí)行默認(rèn)的處理動(dòng)作。5 M- M# o8 z3 o/ Z) p" T
6 O* }9 L5 a$ r' e; l
當(dāng)一個(gè)進(jìn)程使用 fork() 系統(tǒng)調(diào)用創(chuàng)建一個(gè)子進(jìn)程時(shí),子進(jìn)程會(huì)繼承父進(jìn)程的信號(hào)處理方式。由于子進(jìn)程是通過(guò)復(fù)制父進(jìn)程的內(nèi)存映像而創(chuàng)建的,所以信號(hào)捕獲函數(shù)的地址在子進(jìn)程中同樣有效。這意味著子進(jìn)程將會(huì)繼承父進(jìn)程的信號(hào)處理函數(shù)和其他相關(guān)的信號(hào)處理狀態(tài)。) V" y3 |7 U# m3 s( w1 H3 q7 w
' u4 E7 `4 `' ?! s8 V+ s這種繼承機(jī)制確保了子進(jìn)程在初始狀態(tài)下能夠正確處理信號(hào),避免因?yàn)槲炊x的信號(hào)處理而導(dǎo)致不可預(yù)測(cè)的行為。如果需要,子進(jìn)程可以在運(yùn)行過(guò)程中修改其信號(hào)處理方式,從而實(shí)現(xiàn)特定的行為需求。
4 b; S3 g4 O# R+ e# N+ s1 u5 v5 u9 j" L! y7 A
在設(shè)計(jì)信號(hào)處理函數(shù)時(shí),通常建議保持其簡(jiǎn)單性。這與設(shè)計(jì)中斷處理函數(shù)的原則相似:處理函數(shù)應(yīng)盡可能簡(jiǎn)短和高效,避免執(zhí)行大量耗費(fèi) CPU 時(shí)間的操作。& L6 t, P r. F0 I" V6 a- H2 [0 b# l! L* C
主要原因如下:( b1 n+ [! [0 r5 U, K5 {
- O4 @. u5 @% \' @, [減少信號(hào)競(jìng)爭(zhēng)條件:信號(hào)競(jìng)爭(zhēng)條件(Race Condition)指的是在多線程或多進(jìn)程環(huán)境中,不同信號(hào)可能在不合適的時(shí)間內(nèi)打斷正在處理的代碼,導(dǎo)致不可預(yù)測(cè)的結(jié)果。如果信號(hào)處理函數(shù)復(fù)雜且耗時(shí)較長(zhǎng),進(jìn)程在執(zhí)行處理函數(shù)時(shí),可能會(huì)接收到相同或其他信號(hào),增加競(jìng)爭(zhēng)條件發(fā)生的風(fēng)險(xiǎn)。保證系統(tǒng)響應(yīng)性:信號(hào)處理函數(shù)應(yīng)快速完成,以確保系統(tǒng)能夠及時(shí)響應(yīng)其他事件或信號(hào)。如果處理函數(shù)占用了大量的 CPU 時(shí)間,系統(tǒng)響應(yīng)速度可能會(huì)受到影響,尤其是在實(shí)時(shí)性要求較高的系統(tǒng)中。減少對(duì)系統(tǒng)狀態(tài)的影響:復(fù)雜的信號(hào)處理函數(shù)可能會(huì)改變進(jìn)程的全局狀態(tài)(如修改全局變量),這可能會(huì)導(dǎo)致進(jìn)程在信號(hào)處理完成后進(jìn)入不一致的狀態(tài)。因此,簡(jiǎn)單的處理函數(shù)可以減少這些副作用。
4 R; Q. j1 J8 o7 a9 y! Y% [; x: b+ R' m
最佳實(shí)踐:9 Q+ P, k$ G8 |$ F9 p4 x
在信號(hào)處理函數(shù)中,只執(zhí)行必要的操作,如設(shè)置一個(gè)標(biāo)志或記錄一個(gè)簡(jiǎn)單的狀態(tài)。如果需要執(zhí)行復(fù)雜的邏輯,可以在信號(hào)處理函數(shù)中設(shè)置一個(gè)標(biāo)志,然后在主程序的主循環(huán)中檢查該標(biāo)志,并執(zhí)行相應(yīng)的復(fù)雜邏輯。
$ p! o0 G. l& J這種方式可以有效分離信號(hào)處理與復(fù)雜邏輯,降低風(fēng)險(xiǎn)。
, E$ }' m/ v# P4 I$ K8 Y
5 L, [8 l3 L3 ^通過(guò)保持信號(hào)處理函數(shù)的簡(jiǎn)單性,你可以有效提高程序的穩(wěn)定性和可靠性,減少潛在的問(wèn)題和復(fù)雜的調(diào)試過(guò)程。
0 E: d$ E+ j; }# H2 c3 I/ `( N/ \) C2 \$ ]1 S( m1 |$ f
kulnfpoytpx64014084608.jpg (71.14 KB, 下載次數(shù): 1)
下載附件
保存到相冊(cè)
kulnfpoytpx64014084608.jpg
2024-9-1 11:37 上傳
* ], r* j# {4 Y4 S9 J* Q& `/ b+ S; L
cwz5au3qluk64014084708.gif (45.46 KB, 下載次數(shù): 1)
下載附件
保存到相冊(cè)
cwz5au3qluk64014084708.gif
2024-9-1 11:37 上傳
- o9 w% Y- x2 g' C* u
點(diǎn)擊閱讀原文,更精彩~ |
|