日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux信号实践(3) --信号内核表示

發布時間:2023/12/9 linux 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux信号实践(3) --信号内核表示 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

信號在內核中的表示

? ?執行信號的處理動作稱為信號遞達(Delivery),信號從產生到遞達之間的狀態,稱為信號未決(Pending)。進程可以選擇阻塞(Block)某個信號。被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。

? ?注意,阻塞和忽略是不同,只要信號被阻塞就不會遞達,而忽略是在遞達之后可選的一種處理動作。信號在內核中的表示可以看作是這樣的:

?

圖-信號的發送過程

?

解釋說明:

? 1)PCB進程控制塊(task_struct)中函數有信號屏蔽狀態字(block)信號未決狀態字(pending)還有是否忽略標志

? 2) 信號屏蔽狀態字(block),?1代表阻塞、0代表不阻塞;

? ? ? 信號未決狀態字(pending)的1代表未決,0代表信號可以抵達了;

? 3)向進程發送SIGINT,內核首先判斷信號屏蔽狀態字是否阻塞,若阻塞,信號未決狀態字(pending)相應位制成1;若阻塞解除,信號未決狀態字(pending)相應位制成0;表示信號可以抵達了。

? 4)block狀態字、pending狀態字均64位(bit);

? 5)block狀態字用戶可以讀寫,pending狀態字用戶只能讀;這是信號設計機制

?

? 思考1:狀態字都64bit,編程時,如何表示狀態字那?

??思考2:block狀態字信息如何獲取或者操作那?哪些api?

??思考3:pending狀態字信息如何獲取或者操作那?哪些api?

????答案見下;

?

信號集操作函數(狀態字表示)?

#include <signal.h> int sigemptyset(sigset_t *set); //把信號集清零;(64bit/8=8字節) int sigfillset(sigset_t *set); //把信號集64bit全部置為1 int sigaddset(sigset_t *set, int signo); //根據signo,把信號集中的對應位置成1 int sigdelset(sigset_t *set, int signo); //根據signo,把信號集中的對應位置成0 int sigismember(const sigset_t *set, int signo); //判斷signo是否在信號集中

sigprocmask:讀取/更改信號屏蔽狀態字(Block)

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

返回值:若成功則為0,若出錯則為-1

? 讀取:如果oset是非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。

? 更改:如果set是非空指針,則更改進程的信號屏蔽字,參數how指示如何更改。如果oset和set都是非空指針,則先將原來的信號屏蔽字備份到oset里,然后根據set和how參數更改信號屏蔽字。假設當前的信號屏蔽字為mask,下表說明了how參數的可選值。

How:

?

?

sigpending獲取信號未決狀態字(pending)信息?

#include <signal.h> int sigpending(sigset_t *set);

DESCRIPTION

?sigpending()??returns?the?set?of?signals?that?are?pending?for?delivery?to?the?calling?thread?

(i.e.,?the?signals?which?have?been?raised?while?blocked).??

The?mask?of?pending?signals?is?returned?in?set.

/** 示例1:添加信號SIGINT到信號屏蔽字 此時再按下Ctrl+C鍵, 進程也接收不到SIGINT信號了 **/ inline void err_exit(std::string message); void sigHandler(int signo); void printSigSet(const sigset_t &sigset);int main() { //雖然此處安裝了信號處理函數, 但是該進程還是接收不到SIGINT信號if (signal(SIGINT, sigHandler) == SIG_ERR)err_exit("signal error");//添加信號屏蔽字: 屏蔽SIGINT信號sigset_t addset;sigemptyset(&addset);sigaddset(&addset, SIGINT);if (sigprocmask(SIG_BLOCK, &addset, NULL) == -1)err_exit("sigprocmask error");// 不斷打印當前的信號屏蔽字sigset_t sigset;while (true){sigpending(&sigset);printSigSet(sigset);sleep(1);} }inline void err_exit(std::string message) {perror(message.c_str());exit(EXIT_FAILURE); } void sigHandler(int signo) {cout << "catch a signal, number = " << signo << endl; } void printSigSet(const sigset_t &sigset) {for (unsigned i = 1; i < NSIG; ++i){if (sigismember(&sigset, i))putchar('1');elseputchar('0');}putchar('\n'); }/** 示例2:在示例1的基礎上繼續屏蔽SIGINT信號, 但是如果該進程接收到了SIGQUIT信號, 則將對SIGINT信號的屏蔽解除, 需要 1.在main函數中再安裝一個SIGQUIT捕捉函數 2.對sigHandler函數進行改造 **/ int main() {if (signal(SIGINT, sigHandler) == SIG_ERR)err_exit("signal SIGINT error");if (signal(SIGQUIT, sigHandler) == SIG_ERR)err_exit("signal SIGQUIT error");//添加信號屏蔽字: 屏蔽SIGINT信號sigset_t addset;sigemptyset(&addset);sigaddset(&addset, SIGINT);if (sigprocmask(SIG_BLOCK, &addset, NULL) == -1)err_exit("sigprocmask error");// 不斷打印當前的信號屏蔽字sigset_t sigset;while (true){sigpending(&sigset);printSigSet(sigset);sleep(1);} }void sigHandler(int signo) {switch (signo){case SIGINT:cout << "catch a signal SIGINT" << endl;break;case SIGQUIT://如果是SIGQUIT信號, 則將SIGINT信號的屏蔽進行解除sigset_t unblockSet;sigemptyset(&unblockSet);sigaddset(&unblockSet, SIGINT);if (sigprocmask(SIG_UNBLOCK, &unblockSet, NULL) == -1)err_exit("sigprocmask unblock error");elsecout << "sigprocmask success" << endl;break;default:cerr << "unknown signal" << endl;break;} } /**連續的按Ctrl+c鍵盤,雖然發送了多個SIGINT信號,但是因為信號是不穩定的(不支持排隊),所以只保留了一個,如下圖 */

//示例: 換成實時信號SIGRTMAX int main() {if (signal(SIGRTMAX, sigHandler) == SIG_ERR)err_exit("signal SIGRTMAX error");if (signal(SIGQUIT, sigHandler) == SIG_ERR)err_exit("signal SIGQUIT error");//添加信號屏蔽字: 屏蔽SIGRTMAX信號sigset_t addset;sigemptyset(&addset);sigaddset(&addset, SIGRTMAX);if (sigprocmask(SIG_BLOCK, &addset, NULL) == -1)err_exit("sigprocmask error");// 不斷打印當前的信號屏蔽字sigset_t sigset;while (true){sigpending(&sigset);printSigSet(sigset);sleep(1);} } void sigHandler(int signo) {if (signo == SIGRTMAX)cout << "catch a signal SIGRTMAX" << endl;else if (signo == SIGQUIT){sigset_t unblockSet;sigemptyset(&unblockSet);sigaddset(&unblockSet, SIGRTMAX);if (sigprocmask(SIG_UNBLOCK, &unblockSet, NULL) == -1)err_exit("sigprocmask unblock error");elsecout << "sigprocmask success" << endl;}elsecerr << "unknown signal" << endl; }

/**?向該進程連續發送四個SIGRTMAX,?則進程都能夠收到**/

?

?

綜合案例

? ?1)?創建子進程與父進程;

? ?2)?注冊SIGINT非實時信號與SIGRTMIN實時信號,并將這兩種信號添加到進程屏蔽信號組中;

? ?3)?注冊用戶自定義信號;

? ?4)?子進程發送5次非實時信號,發5次實時信號;

? ?5)?然后子進程發送SIGUSR1解除進程對SIGINT,SIGTRMIN信號的阻塞

? ?6)?觀察實時信號與非實時信號的區別

//程序示例 void onSigAction(int signalNumber, siginfo_t *sigInfoStruct, void *) {//獲取接收到的數據int receiveNumber = sigInfoStruct->si_int;//如果收到的是SIGUSR1信號,則解除對SIGINT,SIGRTMIN的屏蔽if (signalNumber == SIGUSR1){sigset_t unblockSet;sigemptyset(&unblockSet);sigaddset(&unblockSet,SIGINT);sigaddset(&unblockSet,SIGRTMIN);;sigprocmask(SIG_UNBLOCK,&unblockSet,NULL);//Value值會是亂碼!//cout << "Receive SIGUSR1, Value = " << receiveNumber << endl;cout << "Unblock, Receive SIGUSR1" << endl;}else if (signalNumber == SIGINT){cout << "Receive SIGINT, Value = " << receiveNumber << endl;}else if (signalNumber == SIGRTMIN){cout << "Receive SIGRTMIN, Value = " << receiveNumber << endl;} }int main() {struct sigaction act;//如果需要使得信號處理程序接收額外數據,//則必須將sa_flags位置為SA_SIGINFOact.sa_flags = SA_SIGINFO;sigemptyset(&act.sa_mask);act.sa_sigaction = onSigAction;//注冊信號處理函數if (sigaction(SIGINT,&act,NULL) < 0)err_exit("sigaction SIGINT");if (sigaction(SIGRTMIN,&act,NULL) < 0)err_exit("sigaction SIGRTMIN");if (sigaction(SIGUSR1,&act,NULL) < 0)err_exit("sigaction SIGUSR1");//將信號SIGINT,SIGRTMIN信號阻塞sigset_t blockSet;sigemptyset(&blockSet);sigaddset(&blockSet,SIGINT);sigaddset(&blockSet,SIGRTMIN);if (sigprocmask(SIG_BLOCK,&blockSet,NULL) < 0)err_exit("sigprocmask error");pid_t pid = fork();if (pid == -1)err_exit("fork error");else if (pid == 0){union sigval Value;Value.sival_int = 200;//給父進程發送五次帶額外數據的非可靠信號(其實最終只接受到了一次)for (int i = 0; i < 5; ++i){++ Value.sival_int;if (sigqueue(getppid(),SIGINT,Value) != 0)err_exit("sigqueue error");}//給父進程發送五次帶額外數據的可靠信號(最終接收到了五次!!!)Value.sival_int = 0;for (int i = 0; i < 5; ++i){++ Value.sival_int;if (sigqueue(getppid(),SIGRTMIN,Value) != 0)err_exit("sigqueue error");}//給父進程發送SIGUSR1信號,解除對SIGINT,SIGRTMIN信號的阻塞kill(getppid(),SIGUSR1);}while (true){pause();} }

運行結果:

?

?其實只是收到了一份非可靠信號SIGINT!

轉載于:https://www.cnblogs.com/itrena/p/5926969.html

總結

以上是生活随笔為你收集整理的Linux信号实践(3) --信号内核表示的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。