【操作系統】信號處理與阻塞函數|時序競態問題

🔥博客主頁:?我要成為C++領域大神
🎥系列專欄:【C++核心編程】?【計算機網絡】?【Linux編程】?【操作系統】
??感謝大家點贊👍收藏?評論??

本博客致力于知識分享,與更多的人進行學習交流

?

關于阻塞函數和信號處理沖突

阻塞函數處于等待狀態,等待系統通知或事件消息,如果接收到信號,信號處理函數會中斷阻塞函數的執行。這可能導致阻塞函數提前返回。

下面是這一現象的demo程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <signal.h>void sigint(int signo)
{printf("捕捉到了SIGINT %d號信號\n",signo);
}int main()
{struct sigaction act,oact;act.sa_handler=sigint;act.sa_flags=0;sigemptyset(&act.sa_mask);sigaction(SIGINT,&act,&oact);char buffer[1024];bzero(buffer,sizeof(buffer));int len;
TryAgain:while((len=read(STDIN_FILENO,buffer,sizeof(buffer)))>0){write(STDOUT_FILENO,buffer,sizeof(buffer));bzero(buffer,sizeof(buffer));}if(len==-1){printf("阻塞函數被信號中斷,TryAgain。。。\n");goto TryAgain;}return 0;
}

時序競態

什么是時序競態?將同一個程序執行兩次,正常情況下,前后兩次執行得到的結果應該是一樣的。但由于系統資源競爭的原因,前后兩次執行的結果有可能得到不一樣的結果,這個現象就是時序競態。

pause函數

進程調用pause函數時,會造成進程主動掛起(處于阻塞狀態,并主動放棄CPU),并且等待信號將其喚醒。

信號的處理方式有三種:1. 默認;2. 忽略;3. 捕捉。進程收到一個信號后,會先處理響應信號,再喚醒pause函數。于是有下面幾種情況:

① 如果信號的默認處理動作是終止進程,則進程將被終止,也就是說一收到信號進程就終止了,pause函數根本就沒有機會返回;

② 如果信號的默認處理動作是忽略,則進程將直接忽略該信號,相當于沒收到這個信號,進程繼續處于掛起狀態,pause函數不返回;

③ 如果信號的處理動作是捕捉,則進程調用完信號處理函數之后,pause返回-1,errno設置為EINTR,表示“被信號中斷”。

④ pause收到的信號不能被屏蔽,如果被屏蔽,那么pause就不能被喚醒。

因為alarm函數可以在設定的時間之后發送SIGALRM信號,pause函數又可以將進程掛起等待信號,則二者結合可以自己寫一個sleep函數

#include <stdio.h>
#include <unistd.h>
#include <signal.h>void sig_alrm(int signo)
{/*空調用,僅負責捕捉,防止信號殺死進程*/
}unsigned int mysleep(unsigned int sec)
{signal(SIGALRM,sig_alrm);unsigned int sleptSec=alarm(sec);//設置一個定時器,定時器結束后發送SIGALRM信號int retNum=pause();//設置進程主動掛起,等待信號將其喚醒。信號的處理行為是捕捉,調用完捕捉函數后返回-1printf("%d\n",retNum);return sleptSec;
}int main()
{while(1){mysleep(2);printf("2s Passed\n");}return 0;
}

pause的返回值是-1

時序競態問題分析

SIGALRM默認動作是終止進程,因此我們要將其捕捉,對SIGALRM注冊信號處理函數;

調用alarm(1)函數定時1秒鐘;

alarm(1)調用結束,定時器開始計時。調用完alarm后立即調用了sleep函數,因為調用了系統函數,所以會發生內核層切換,進程失去CPU,進入就緒態等待CPU。使得當前進程無法獲得CPU;

alarm函數采用自然定時法,定時器將一直計時,與進程狀態無關。于是,1秒后,鬧鐘定時時間到,內核向當前進程發送SIGALRM信號。

sleep函數調用完畢后,返回進程前,會檢測一下是否有未處理的信號,檢測到了SIGALRM信號并進行捕捉處理。

信號處理完畢后,返回當前主控流程,并調用pause()函數,掛起等待alarm函數發送的SIGALRM信號將自己喚醒;

但實際SIGALRM信號已經處理完畢,pause()函數永遠不會等到,于是就永遠掛起了。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>void sig_alrm(int signo)
{/*空調用,僅負責捕捉,防止信號殺死進程*/
}unsigned int mysleep(unsigned int sec)
{signal(SIGALRM,sig_alrm);unsigned int sleptSec=alarm(sec);//設置一個定時器,定時器結束后發送SIGALRM信號sleep(3);//對SIGALRM進行了處理,導致了進程被永遠掛起pause();//設置進程主動掛起,等待信號將其喚醒。信號的處理行為是捕捉,調用完捕捉函數后返回-1return sleptSec;
}int main()
{while(1){mysleep(2);printf("2s Passed\n");}return 0;
}

運行結果:由于pause收不到SIGALRM信號,所以被一直掛起了

解決時序競態問題

在調用sleep函數之前,屏蔽SIGALRM信號,防止sleep對信號進行處理。在sleep調用完成之后,解除對SIGALRM的屏蔽,然后pause()掛起進程等待SIGALRM將其喚醒。

但在解除屏蔽與pause等待掛起信號之間,還是有可能進行其他操作處理SIGALRM,除非將這兩個步驟做成一個“原子操作”。Linux系統提供的sigsuspend函數就具備這個功能。所以,在時序要求比較嚴格的場合下都應該使用sigsuspend函數,而非pause函數。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <signal.h>void sig_alarm(int signo)
{//null 空調用
}unsigned int mysleep(unsigned int seconds)
{//設置捕捉函數struct sigaction act,oldact;act.sa_handler=sig_alarm;act.sa_flags=0;sigemptyset(&act.sa_mask);sigaction(SIGALRM,&act,&oldact);//設置信號屏蔽sigset_t set,oldset;sigemptyset(&set);sigaddset(&set,SIGALRM);sigprocmask(SIG_SETMASK,&set,&oldset);alarm(2);sleep(3);sigsuspend(&act.sa_mask);
}int main()
{while(1){mysleep(2);printf("two seconds\n");}return 0;
}

Shell腳本實現進程的外部控制

實現一個Shell腳本來對進程進行外部控制,可以使用信號機制來控制進程的啟動、停止和繼續運行 。Windows常用的任務管理器就是這個機制,利用外部控制的信號來實現進程的掛起、終止、提高優先級等。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <signal.h>void sig_stop(int n)//捕捉SIGUSR1信號
{printf("進程已被殺死\n");exit(0);
}void sig_count(int n)
{printf("進程已被掛起\n");pause();
}void test_sigaction(void)
{struct sigaction act,bct,oact;act.sa_handler=sig_stop;act.sa_flags=0;sigemptyset(&act.sa_mask);sigaction(SIGUSR1,&act,&oact);bct.sa_handler=sig_count;bct.sa_flags=0;sigemptyset(&bct.sa_mask);sigaction(SIGUSR2,&bct,NULL);
}void output_pid(void)
{int fd=open("config.conf",O_RDWR|O_CREAT,0664);pid_t pid=getpid();char id[10];bzero(id,sizeof(id));sprintf(id,"%d",pid);write(fd,id,strlen(id));close(fd);
}
int main()
{test_sigaction();//設定捕捉output_pid();while(1){printf("this is test...\n");sleep(2);}return 0;
}
#!/bin/bashPID=$(cat config.conf)if [ $1=="stop" ]
then kill -10 $PID #發送SIGUSR1信號
elif [ $1=="cont" ]
then kill -12 $PID #發送SIGUSR2信號
else print "control call faild\n"
fi

運行結果:通過外部腳本成功殺死進程

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35062.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35062.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35062.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Windows環境部署MySQL_8.4.0 LTS的部署安裝、驗證連接以及卸載全過程實操手冊

前言&#xff1a; 什么是 MySQL MySQL 是一個關系型數據庫管理系統&#xff0c;由瑞典 MySQL AB 公司開發&#xff0c;目前屬于Oracle 公司。MySQL 是一種關系型數據庫管理系統&#xff0c;關系型數據庫將數據保存在不同的表中&#xff0c;而不是將所有數據放在一個大倉庫內&am…

secureCRT中使用python腳本自動化測試vela設備

利用vela設備自帶的wapi命令行&#xff0c;重復執行聯網斷網的命令&#xff0c;測試系統穩定性。 實現如下&#xff0c; # $language "python" # $interface "1.0"# This automatically generated script may need to be # edited in order to work co…

8.12 矢量圖層面要素單一符號使用七(隨機標記填充)

文章目錄 前言隨機標記填充&#xff08;Random Marker Fill&#xff09;QGis設置面符號為隨機標記填充&#xff08;Random Marker Fill&#xff09;二次開發代碼實現隨機標記填充&#xff08;Random Marker Fill&#xff09; 總結 前言 本章介紹矢量圖層線要素單一符號中使用隨…

分班查詢怎么發布?

在現代教育環境中&#xff0c;傳統的學生分班通知方式可能顯得有些過時和低效。通常&#xff0c;這些方式依賴于紙質通知單&#xff0c;這不僅需要大量的物理資源進行打印和分發&#xff0c;而且容易出錯&#xff0c;如丟失、錯誤分發或延遲。 幸運的是&#xff0c;現在有了更高…

掌握Perl并發:線程與進程編程全攻略

掌握Perl并發&#xff1a;線程與進程編程全攻略 引言 Perl作為一種功能強大的編程語言&#xff0c;提供了豐富的并發編程手段。無論是通過threads模塊實現的線程&#xff0c;還是通過fork系統調用產生的進程&#xff0c;Perl都能幫助開發者高效地處理多任務。本文將深入探討如…

解釋Java的垃圾回收機制以及垃圾回收器的工作原理。

Java的垃圾回收機制&#xff08;Garbage Collection&#xff0c;GC&#xff09;是Java虛擬機&#xff08;JVM&#xff09;的一個重要組成部分&#xff0c;它負責自動管理內存&#xff0c;確保內存泄漏和內存溢出錯誤不會發生。垃圾回收器&#xff08;Garbage Collector&#xf…

心靈館咨詢系統小程序心理咨詢平臺聊天咨詢

心靈館咨詢系統小程序&#xff1a;解鎖你的心靈密碼 &#x1f496; 心靈之旅的導航者 在繁忙的現代生活中&#xff0c;我們時常會面臨各種壓力與困惑。心靈館咨詢系統小程序&#xff0c;如同一位貼心的導航者&#xff0c;引領我們探索內心的世界&#xff0c;尋找真正的自我。 …

shell 腳本的部分指令和操作符

終端輸入兩個數&#xff0c;判斷兩數是否相等&#xff0c;如果不相等&#xff0c;判斷大小關系 2.已知網址www.hqyj.com&#xff0c;使用expr截取出www、hqyj、com&#xff0c;不能使用cut&#xff0c;不能出現數字

JavaWeb系列十九: jQuery的DOM操作 上

查找節點, 修改屬性 查找屬性節點: 查找到所需要的元素之后, 可以調用jQuery對象的attr()方法用來 設置/返回 它的各種屬性值 設置屬性值 $(“img”).attr(“width”, “300”);返回屬性值 $(“img”).attr(“width”); 創建節點 創建節點: 使用jQuery的工廠函數$(): $(html標…

硬核實力再亮,玩出夢想科技發布全球首款安卓系統空間計算機

6月25日&#xff0c;玩出夢想科技在新加坡召開全球新品發布會&#xff0c;正式發布全球首款安卓系統空間計算機——玩出夢想MR&#xff0c;填補了空間計算機在安卓生態的空白。 作為品牌沉淀兩年的破曉之作&#xff0c;玩出夢想MR以業內領先軟硬件配置&#xff0c;強大自研算法…

刪除win10未激活水印

通過終止進程來刪除水印 remove.batecho off taskkill /F /IM explorer.exe explorer.exe exit右鍵管理員執行重啟

解決了!暗影精靈8 Pro酷睿版無聲音,揚聲器和麥克風都沒有聲音!

困擾好幾天的問題解決了&#xff01; 暗影精靈8 Pro酷睿版無聲音&#xff0c;揚聲器和麥克風都沒有聲音&#xff01;&#xff01;方法適用于OMEN by HP Gaming Laptop 16-k0xxx&#xff08;暗影精靈8 Pro酷睿版&#xff09;的Windows 10聲卡驅動&#xff01; 朋友們&#xff…

【應用開發一】LED開發

文章目錄 1應用層控制外設的兩種方式2 sysfs和/sys關系3 LED控制方式3.1 基本情況3.2 LED屬性文件介紹3.3 命令行屬性測試3.4 led程序3.5 開發板上測試 1應用層控制外設的兩種方式 使用設備文件控制 在Linux系統下&#xff0c;一切皆是文件。應用層控制底層硬件同樣也是通過文…

如何在 Linux 上安裝 Docker Desktop

如何在 Linux 上安裝 Docker Desktop Docker 是一個用于開發、部署和運行應用程序的開放平臺。Docker Desktop 是 Docker 在 macOS 和 Windows 上的官方客戶端&#xff0c;現在也支持 Linux 系統。本文將詳細介紹如何在 Linux 上安裝 Docker Desktop。 系統要求 在開始安裝之…

第100+12步 ChatGPT學習:R實現KNN分類

基于R 4.2.2版本演示 一、寫在前面 有不少大佬問做機器學習分類能不能用R語言&#xff0c;不想學Python咯。 答曰&#xff1a;可&#xff01;用GPT或者Kimi轉一下就得了唄。 加上最近也沒啥內容寫了&#xff0c;就幫各位搬運一下吧。 二、R代碼實現KNN分類 &#xff08;1&a…

【Docker】Consul 和API

目錄 一、Consul 1. 拉取鏡像 2. 啟動第一個consul服務&#xff1a;consul1 3. 查看consul service1 的ip地址 4. 啟動第二個consul服務&#xff1a;consul2&#xff0c; 并加入consul1&#xff08;使用join命令&#xff09; 5. 啟動第三個consul服務&#xff1a;consul3&…

攻擊者開始使用 XLL 文件進行攻擊

近期&#xff0c;研究人員發現使用惡意 Microsoft Excel 加載項&#xff08;XLL&#xff09;文件發起攻擊的行動有所增加&#xff0c;這項技術的 MITRE ATT&CK 技術項編號為 T1137.006。 這些加載項都是為了使用戶能夠利用高性能函數&#xff0c;為 Excel 工作表提供 API …

【SQL Server數據庫】關系模式與關系代數

目錄 一、請用關系代數完成下列查詢 1. 求 供應工程J1 零件P1的供應商號碼SNO&#xff1b; 2. 求 供應工程J1 零件&#xff08;P&#xff09;為紅色 的供應商號碼SNO&#xff1b; 3. 求 沒有使用 天津供應商&#xff08;P&#xff09;生產的紅色零件&#xff08;S&#xff0…

【雜記-淺談OSPF協議之RouterDeadInterval死區間隔】

OSPF協議之RouterDeadInterval死區間隔 一、RouterDeadInterval概述二、設置RouterDeadInterval三、RouterDeadInterval的重要性 一、RouterDeadInterval概述 RouterDeadInterval&#xff0c;即路由器死區間隔&#xff0c;它涉及到路由器如何在廣播網絡上發現和維護鄰居關系。…