新聞中心
在Linux系統(tǒng)中,信號(signal)是一種異步事件的機(jī)制,可以用來通知進(jìn)程發(fā)生了某種事件。Linux系統(tǒng)提供了Signal.h頭文件來支持信號處理機(jī)制,其中包含了各種信號相關(guān)的常量、結(jié)構(gòu)體和函數(shù)。

我們擁有10余年網(wǎng)頁設(shè)計(jì)和網(wǎng)站建設(shè)經(jīng)驗(yàn),從網(wǎng)站策劃到網(wǎng)站制作,我們的網(wǎng)頁設(shè)計(jì)師為您提供的解決方案。為企業(yè)提供成都做網(wǎng)站、成都網(wǎng)站建設(shè)、微信開發(fā)、小程序設(shè)計(jì)、手機(jī)網(wǎng)站制作設(shè)計(jì)、HTML5、等業(yè)務(wù)。無論您有什么樣的網(wǎng)站設(shè)計(jì)或者設(shè)計(jì)方案要求,我們都將富于創(chuàng)造性的提供專業(yè)設(shè)計(jì)服務(wù)并滿足您的需求。
本文將從以下幾個方面,包括信號的基本概念、信號的分類、信號的發(fā)送和接收、信號的處理方式以及信號的應(yīng)用實(shí)例。
一、信號的基本概念
信號是由操作系統(tǒng)發(fā)送給進(jìn)程的一種通知機(jī)制,用于向進(jìn)程發(fā)送各種事件的通知。當(dāng)某個事件發(fā)生時,操作系統(tǒng)會向特定的進(jìn)程發(fā)送相應(yīng)的信號,進(jìn)程可以注冊信號處理函數(shù)來處理這些信號。
Linux系統(tǒng)中有幾十種不同的信號,每一種信號都用一個整數(shù)常量來表示。這些常量定義在Signal.h頭文件中,并以”SIG”開頭。例如,SIGINT表示當(dāng)用戶按下Ctrl+C時發(fā)送給前臺進(jìn)程的信號,SIGTERM表示進(jìn)程終止信號,SIGKILL表示無法處理或終止進(jìn)程的強(qiáng)制終止信號。
二、信號的分類
Linux系統(tǒng)中的信號可以根據(jù)不同的分類方式進(jìn)行分類,其中較為常見的分類方式包括以下幾種:
1.默認(rèn)信號和自定義信號
默認(rèn)信號是由系統(tǒng)定義的且不能被修改的信號,如SIGTERM、SIGKILL等。自定義信號可以由用戶根據(jù)自己的需求來定義,如SIGUSR1、SIGUSR2等。
2.同步信號和異步信號
同步信號是進(jìn)程在執(zhí)行某些操作時自己產(chǎn)生的信號,如除零錯誤、訪問非法地址等。異步信號是由進(jìn)程外部的事件(如按鍵、定時器、網(wǎng)絡(luò)套接字等)觸發(fā)引起的信號。
3.可靠信號和不可靠信號
可靠信號是指能保證信號不會被丟失或重復(fù)發(fā)送的信號。不可靠信號可能會在信號處理函數(shù)還未執(zhí)行完畢時再次被發(fā)送,或者在信號處理函數(shù)中多次發(fā)送。
三、信號的發(fā)送和接收
Linux系統(tǒng)中,進(jìn)程可以使用kill函數(shù)向其他進(jìn)程或自己發(fā)送信號。kill函數(shù)的原型如下:
“`c++
#include
int kill(pid_t pid, int sig);
“`
其中pid參數(shù)表示接收信號的進(jìn)程ID,sig參數(shù)表示發(fā)送的信號。
接收信號的進(jìn)程需要通過signal函數(shù)來注冊信號處理函數(shù),如:
“`c++
#include
void signal_handler(int sig) {
// 處理信號
}
int mn() {
signal(SIGINT, signal_handler); // 注冊鍵盤中斷信號處理函數(shù)
while (1) {
// 循環(huán)等待信號
}
return 0;
}
“`
在本例中,調(diào)用signal函數(shù)來注冊SIGINT信號,并指定了signal_handler作為處理函數(shù)。當(dāng)接收到SIGINT信號時,操作系統(tǒng)會調(diào)用signal_handler處理函數(shù)來處理信號。
四、信號的處理方式
接收到信號之后,操作系統(tǒng)會調(diào)用之前注冊的信號處理函數(shù)來處理信號。關(guān)于信號處理函數(shù)的基本要求如下:
1.信號處理函數(shù)必須是一個C語言函數(shù),返回值為void。
2.信號處理函數(shù)不能有任何參數(shù)。
3.信號處理函數(shù)必須是可重入的,因?yàn)樗赡茉谌魏螘r間被調(diào)用。
信號處理函數(shù)有以下三種處理方式:
1.默認(rèn)處理方式
默認(rèn)處理方式就是不做任何處理,直接忽略信號或終止進(jìn)程??梢允褂胹ignal函數(shù)進(jìn)行設(shè)置,如:
“`c++
#include
signal(SIGINT, SIG_DFL); // 默認(rèn)操作為終止進(jìn)程
“`
2.忽略信號
可以使用signal函數(shù)將信號處理函數(shù)設(shè)置為SIG_IGN來忽略某個信號,如:
“`c++
#include
signal(SIGINT, SIG_IGN); // 忽略鍵盤中斷信號
“`
3.自定義處理方式
可以編寫自定義的信號處理函數(shù)來處理特定的信號,如:
“`c++
#include
void signal_handler(int sig) {
// 處理信號
}
signal(SIGINT, signal_handler); // 注冊鍵盤中斷信號處理函數(shù)
“`
五、信號的應(yīng)用實(shí)例
Linux系統(tǒng)中,信號機(jī)制廣泛應(yīng)用于進(jìn)程間的通信、進(jìn)程控制、時間管理等領(lǐng)域。下面列舉幾個信號的應(yīng)用實(shí)例。
1.進(jìn)程間通信
可以使用kill函數(shù)向其他進(jìn)程發(fā)送自定義信號,如:
“`c++
kill(pid, SIGUSR1); // 向進(jìn)程pid發(fā)送SIGUSR1信號
“`
收到信號的進(jìn)程可以根據(jù)信號類型和來源,決定如何響應(yīng)。例如,可以使用自定義信號來實(shí)現(xiàn)雙方進(jìn)程的心跳檢測、資源分配等功能。
2.進(jìn)程控制
可以使用信號機(jī)制來控制進(jìn)程的行為,例如通過SIGSTOP和SIGCONT信號來停止和繼續(xù)進(jìn)程的執(zhí)行,如:
“`c++
kill(pid, SIGSTOP); // 停止進(jìn)程pid的執(zhí)行
kill(pid, SIGCONT); // 繼續(xù)進(jìn)程pid的執(zhí)行
“`
3.時間管理
可以使用定時器信號來進(jìn)行時間管理,例如使用SIGALRM信號來實(shí)現(xiàn)鬧鐘功能,如:
“`c++
#include
#include
void alarm_handler(int sig) {
// 播放音樂或執(zhí)行其他操作
}
signal(SIGALRM, alarm_handler); // 注冊定時器信號處理函數(shù)
alarm(10); // 10秒后發(fā)送SIGALRM信號
pause(); // 等待定時器信號
“`
在本例中,使用alarm函數(shù)設(shè)置10秒鐘的定時器,當(dāng)定時器到期時,將發(fā)送SIGALRM信號通知進(jìn)程。進(jìn)程在收到SIGALRM信號時,調(diào)用alarm_handler函數(shù)進(jìn)行處理。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗(yàn)豐富以策略為先導(dǎo)10多年以來專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),響應(yīng)式網(wǎng)站制作,設(shè)計(jì)師量身打造品牌風(fēng)格,熱線:028-86922220當(dāng)linux應(yīng)用程序中存在多個異步通知時怎樣處理
驅(qū)動程序運(yùn)行在內(nèi)核空間中,應(yīng)用程序運(yùn)行在用戶空間中,兩者是不能直接通信的。但在實(shí)際應(yīng)用中,在設(shè)備已經(jīng)準(zhǔn)備好的時候,我們希望通知用戶程序搏告坦設(shè)備已經(jīng)ok,用戶程序可以讀取了,這樣應(yīng)用程序就不需要一直查詢該設(shè)備的狀態(tài),從而節(jié)約了資源,這就是異步通知。好,那下一個問題就來了,這個過程如何實(shí)現(xiàn)呢?簡單,兩方面的工作。
一 驅(qū)動方面:
1. 在設(shè)備抽象的數(shù)據(jù)結(jié)構(gòu)中增加一個struct fasync_struct的指針
2. 實(shí)現(xiàn)設(shè)備操作中的fasync函數(shù),這個函數(shù)很簡單,其主體就是調(diào)用內(nèi)核的fasync_helper函數(shù)。
3. 在需要向用戶空間通知的地方(例如中斷中)調(diào)用內(nèi)核的kill_fasync函數(shù)。
4. 在驅(qū)動的release方法中調(diào)用前面定義的fasync函數(shù)
呵呵,簡單吧,就三點(diǎn)。其中fasync_helper和kill_fasync都是內(nèi)核函數(shù),我們只需要調(diào)用就可以了。在
1中定義的指針是一個重要參數(shù),fasync_helper和kill_fasync會使用這個參數(shù)。
二 應(yīng)用層方面
1. 利用signal或者sigaction設(shè)置SIGIO信號的處理函數(shù)
2. fcntl的F_SETOWN指令設(shè)置當(dāng)前進(jìn)程為設(shè)備文件owner
3. fcntl的F_SETFL指令設(shè)置FASYNC標(biāo)志
完成了以上的工作的話,當(dāng)內(nèi)核執(zhí)行到kill_fasync函數(shù),用戶空間SIGIO函數(shù)的處理函數(shù)就會被調(diào)用了。
呵呵,看起來不是很復(fù)雜把,讓我們結(jié)合具體代碼看看就更明白了。
先從應(yīng)用層代碼開始吧:
#include
#include
#include
#include
#include
#include
#define MAX_LEN 100
//處理函數(shù),沒什么好講的,用戶自己定義
void input_handler(int num)
{
char data;
int len;
//讀取并輸出STDIN_FILENO上的輸入
len = read(STDIN_FILENO, &data, MAX_LEN);
data = 0;
printf(“input available:%s\n”, data);
}
void main()
{
int oflags;
//啟動信號驅(qū)動機(jī)制,將SIGIO信號同input_handler函數(shù)關(guān)聯(lián)起來,一旦產(chǎn)生SIGIO信號,就會執(zhí)行input_handler
signal(SIGIO, input_handler);
//STDIN_FILENO是打開的設(shè)備文件描述符,F_SETOWN用來決定操作是干什么的,getpid()是個系統(tǒng)調(diào)用,
//功能是返回當(dāng)前進(jìn)程的進(jìn)程號,整個函數(shù)基桐的功能是STDIN_FILENO設(shè)置這個設(shè)備文件的擁有者為當(dāng)前進(jìn)程。
fcntl(STDIN_FILENO, F_SETOWN, getpid());
//得到打開文件描述符的狀態(tài)
oflags = fcntl(STDIN_FILENO, F_GETFL);
//設(shè)置文件描述符的狀態(tài)為oflags | FASYNC屬性,一旦文件描述符被設(shè)置成具有FASYNC屬性的狀態(tài),
//也就是將設(shè)備文件切換到異步操作模式。這時系統(tǒng)就會自動調(diào)用驅(qū)動程序的fasync方法。
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
//最后進(jìn)入一個死循環(huán),程序什么都不干了,只有信號能激發(fā)input_handler的運(yùn)行
/友凱/如果程序中沒有這個死循環(huán),會立即執(zhí)行完畢
while (1);
}
再看驅(qū)動層代碼,驅(qū)動層其他部分代碼不變,就是增加了一個fasync方法的實(shí)現(xiàn)以及一些改動
//首先是定義一個結(jié)構(gòu)體,其實(shí)這個結(jié)構(gòu)體存放的是一個列表,這個
//列表保存的是一系列設(shè)備文件,SIGIO信號就發(fā)送到這些設(shè)備上
static struct fasync_struct *fasync_queue;
//fasync方法的實(shí)現(xiàn)
static int my_fasync(int fd, struct file * filp, int on)
{
int retval;
//將該設(shè)備登記到fasync_queue隊(duì)列中去
retval=fasync_helper(fd,filp,on,&fasync_queue);
if(retval
{
return retval;
}
return 0;
}
在驅(qū)動的release方法中我們再調(diào)用my_fasync方法
int my_release(struct inode *inode, struct file *filp)
{
//..processing..
drm_fasync(-1, filp, 0);
//..processing..
}
這樣后我們在需要的地方(比如中斷)調(diào)用下面的代碼,就會向fasync_queue隊(duì)列里的設(shè)備發(fā)送SIGIO信號
,應(yīng)用程序收到信號,執(zhí)行處理程序
if (fasync_queue)
kill_fasync(&fasync_queue, SIGIO, POLL_IN);
好了,這下大家知道該怎么用異步通知機(jī)制了吧?
以下是幾點(diǎn)說明:
1 兩個函數(shù)的原型
int fasync_helper(struct inode *inode, struct file *filp, int mode, struct fasync_struct **fa);
一個”幫忙者”, 來實(shí)現(xiàn) fasync 設(shè)備方法. mode 參數(shù)是傳遞給方法的相同的值, 而 fa 指針指向一個設(shè)
備特定的 fasync_struct *
void kill_fasync(struct fasync_struct *fa, int sig, int band);
如果這個驅(qū)動支持異步通知, 這個函數(shù)可用來發(fā)送一個信號到登記在 fa 中的進(jìn)程.
2.
fasync_helper 用來向等待異步信號的設(shè)備鏈表中添加或者刪除設(shè)備文件, kill_fasync被用來通知擁有相關(guān)設(shè)備的進(jìn)程. 它的參數(shù)是被傳遞的信號(常常是 SIGIO)和 band, 這幾乎都是 POLL_IN(但是這可用來發(fā)送”緊急”或者帶外數(shù)據(jù), 在網(wǎng)絡(luò)代碼里).
寫一個linux下寫個關(guān)于c語言的雙守護(hù)進(jìn)程,就是監(jiān)視一個進(jìn)程,當(dāng)其死掉,馬上將其重啟
這判州宴跟execvp函數(shù)的實(shí)現(xiàn)方式有關(guān):
int execvp(const char *file ,char * const argv );
execvp()會從PATH 環(huán)境變量所指的目錄中查找符掘銀合參數(shù)file的文件名,找到后便執(zhí)行該文件,然后將第二個參數(shù)argv傳給該欲執(zhí)行的文件。如果執(zhí)行成功則函數(shù)不會返回,執(zhí)行失敗則直接返回-1,失敗原因存于errno中。
之所以顯示“fail to exec”,是因?yàn)樵赑ATH環(huán)境變量所指的目錄中沒有名為“hello”的程序。建議進(jìn)行如下操作:
1、運(yùn)行“echo $PATH”,查看一跡亂下PATH環(huán)境變量指向那些目錄
2、編寫一個輸出“hello world”的程序,并命名為hello,即執(zhí)行命令:
gcc -o hello hello.c
3、把名為”hello“的程序拷貝到PATH變量所指的其中一個目錄中
可以分三步來做:
做兩個簡單的守護(hù)進(jìn)程,并能正常運(yùn)行
監(jiān)控進(jìn)程是否在運(yùn)行
啟動進(jìn)程
綜合起來就可以了,代碼如下:
被監(jiān)控進(jìn)程thisisatest.c(來自
):
#include
#include
#include
#include
#include
#include
#include
#include
void init_daemon()
{
int pid;
int i;
pid=fork();
if(pid0) //父進(jìn)程退出
exit(0);
setsid(); //使子進(jìn)程成為組長
pid=fork();
if(pid>0)
exit(0); //再次退出,使進(jìn)程不是組長,這樣進(jìn)程就不會打開控制終端
else if(pid=0)
{
time(&t);
豎族 fprintf(fp,”current time is:%s\n”,asctime(localtime(&t))); //轉(zhuǎn)換為本地時間輸出
fclose(fp);
}
}
return;
}
監(jiān)控進(jìn)程monitor.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFSZ 150
void init_daemon()
{
int pid;
int i;
pid=fork();
if(pid0) //父進(jìn)程退出
exit(0);
setsid(); //使子進(jìn)程成為組長
pid=fork();
if(pid>0)
exit(0); //再次退出,使進(jìn)程不是組長,這樣進(jìn)程就不會打開控制終端
else if(pid=0)
{
count = does_service_work();
time(&t);
if(count>0)
fprintf(fp,”current time is:%s and the process exists, the count is %d\n”,asctime(localtime(&t)), count); //轉(zhuǎn)換為本地時間輸出
else
{
fprintf(fp,”current time is:%s and the process does not exist, restart it!\n”,asctime(localtime(&t))); //轉(zhuǎn)換為本地時間輸出
system(“/home/user/daemon/thisisatest”); //啟動服務(wù)
}
fclose(fp);
}
}
return;
}
具體CMD命令:
cc thisisatest.c -o thisisatest
./thisisatest
cc monitor.c -o monitor
./monitor
tail -f testfork3.log — 查看日志
linux signal.h的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于linux signal.h,深入探索Linux Signal.h信號處理機(jī)制,當(dāng)linux應(yīng)用程序中存在多個異步通知時怎樣處理,寫一個linux下寫個關(guān)于c語言的雙守護(hù)進(jìn)程,就是監(jiān)視一個進(jìn)程,當(dāng)其死掉,馬上將其重啟的信息別忘了在本站進(jìn)行查找喔。
成都創(chuàng)新互聯(lián)科技公司主營:網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、小程序制作、成都軟件開發(fā)、網(wǎng)頁設(shè)計(jì)、微信開發(fā)、成都小程序開發(fā)、網(wǎng)站制作、網(wǎng)站開發(fā)等業(yè)務(wù),是專業(yè)的成都做小程序公司、成都網(wǎng)站建設(shè)公司、成都做網(wǎng)站的公司。創(chuàng)新互聯(lián)公司集小程序制作創(chuàng)意,網(wǎng)站制作策劃,畫冊、網(wǎng)頁、VI設(shè)計(jì),網(wǎng)站、軟件、微信、小程序開發(fā)于一體。
分享文章:深入探索LinuxSignal.h信號處理機(jī)制(linuxsignal.h)
分享URL:http://www.dlmjj.cn/article/cddesij.html


咨詢
建站咨詢
