【Linux系統化學習】信號的保存

目錄

阻塞信號

信號處理常見方式概覽

信號的其他相關概念

在內核中的表示

sigset_t

信號集操作函數

sigprocmask函數

sigpending函數

信號的捕捉

內核如何實現信號的捕捉

sigaction函數

可重入函數

volatile


阻塞信號

信號處理常見方式概覽

當信號來臨時,進程可以有這三個處理動作:

1. 忽略此信號。
2. 執行該信號的默認處理動作。
3. 提供一個信號處理函數,要求內核在處理該信號時切換到用戶態執行這個處理函數,這種方式稱為捕捉(Catch)一個信號。

  1 #include<iostream>  2 #include<signal.h>  3 using namespace std;  4 int main()  5 {6     signal(2,SIG_IGN);7     signal(2,SIG_DFL);8     signal(2,nullptr);                                             9     return 0;                                   10 }

我們可以使用signal對信號進行捕捉,選擇處理動作;分別是忽略(SIG_IGN)、默認(SIG_DFL)、自定義方式;參數為一個返回值為void參數為int的函數指針。

信號的其他相關概念

  • 實際執行信號的處理動作稱為信號遞達(Delivery)
  • 信號從產生到遞達之間的狀態,稱為信號未決(Pending)。
  • 進程可以選擇阻塞 (Block )某個信號。
  • 被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作.
  • 注意,阻塞和忽略是不同的,只要信號被阻塞就不會遞達,而忽略是在遞達之后可選的一種處理動作

在內核中的表示

?

每個信號都有兩個標志位分別表示阻塞(block)和未決(pending),還有一個函數指針表示處理動作。信號產生時,內核在進程控制塊中設置該信號的未決標志,直到信號遞達才清除該標志。在上圖的例子中,SIGHUP信號未阻塞也未產生過,當它遞達時執行默認處理動作。

SIGINT信號產生過,但正在被阻塞,所以暫時不能遞達。雖然它的處理動作是忽略,但在沒有解除阻塞之前不能忽略這個信號,因為進程仍有機會改變處理動作之后再解除阻塞。

SIGQUIT信號未產生過,一旦產生SIGQUIT信號將被阻塞,它的處理動作是用戶自定義函數sighandler。如果在進程解除對某信號的阻塞之前這種信號產生過多次,將如何處理?POSIX.1允許系統遞送該信號一次或多次。Linux是這樣實現的:常規信號在遞達之前產生多次只計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列里。

sigset_t

從上圖來看,每個信號只有一個bit的未決標志,非0即1,不記錄該信號產生了多少次,阻塞標志也是這樣表示的。因此,未決和阻塞標志可以用相同的數據類型sigset_t來存儲,sigset_t稱為信號集,這個類型可以表示每個信號的“有效”或“無效”狀態,在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有效”和“無效”的含義是該信號是否處于未決狀態。下一節將詳細介紹信號集的各種操作。 阻塞信號集也叫做當前進程的信號屏蔽字(Signal Mask),這里的“屏蔽”應該理解為阻塞而不是忽略。

信號集操作函數

sigset_t類型對于每種信號用一個bit表示“有效”或“無效”狀態,至于這個類型內部如何存儲這些bit則依賴于系統實現,從使用者的角度是不必關心的,使用者只能調用以下函數來操作sigset_ t變量,而不應該對它的內部數據做任何解釋,比如用printf直接打印sigset_t變量是沒有意義的。

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
  • 函數sigemptyset初始化set所指向的信號集,使其中所有信號的對應bit清零,表示該信號集不包含 任何有效信號。
  • 函數sigfillset初始化set所指向的信號集,使其中所有信號的對應bit置位,表示 該信號集的有效信號包括系統支持的所有信號。
  • 注意,在使用sigset_ t類型的變量之前,一定要調 用sigemptyset或sigfillset做初始化,使信號集處于確定的狀態。初始化sigset_t變量之后就可以在調用sigaddset和sigdelset在該信號集中添加或刪除某種有效信號。

這四個函數都是成功返回0,出錯返回-1。sigismember是一個布爾函數,用于判斷一個信號集的有效信號中是否包含某種 信號,若包含則返回1,不包含則返回0,出錯返回-1。

sigprocmask函數

調用函數sigprocmask可以讀取或更改進程的信號屏蔽字(阻塞信號集)。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功則為0,若出錯則為-1

如果調用sigprocmask解除了對當前若干個未決信號的阻塞,則在sigprocmask返回前,至少將其中一個信號遞達。

sigpending函數

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

讀取當前進程的未決信號集,通過set參數傳出。調用成功則返回0,出錯則返回-1。 下面用剛學的幾個函數做個實驗。?

程序運行時,每秒鐘把各信號的未決狀態打印一遍,由于我們阻塞了SIGINT信號,按Ctrl-C將會 使SIGINT信號處于未決狀態,按Ctrl-\仍然可以終止程序,因為SIGQUIT信號沒有阻塞。?

信號的捕捉

內核如何實現信號的捕捉

如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個函數,這稱為捕捉信號。由于信號處理函數的代碼是在用戶空間的,處理過程比較復雜,舉例如下: 用戶程序注冊了SIGQUIT信號的處理函數sighandler。 當前正在執行main函數,這時發生中斷或異常切換到內核態。 在中斷處理完畢后要返回用戶態的main函數之前檢查到有信號SIGQUIT遞達。 內核決定返回用戶態后不是恢復main函數的上下文繼續執行,而是執行sighandler函 數,sighandler和main函數使用不同的堆棧空間,它們之間不存在調用和被調用的關系,是 兩個獨立的控制流程。 sighandler函數返回后自動執行特殊的系統調用sigreturn再次進入內核態。 如果沒有新的信號要遞達,這次再返回用戶態就是恢復
main函數的上下文繼續執行了。

總結:

  • 用戶態是一種受控制的狀態,能夠訪問的資源是有限的。
  • 內核態是一種操作系統的工作狀態,能夠訪問大部分的系統資源。
  • 進程從內核態返回到用戶態的時候,進行信號的檢測和信號的處理。信號捕捉中一個進程最少要進行四次身份轉換。

sigaction函數

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

sigaction函數可以讀取和修改與指定信號相關聯的處理動作。調用成功則返回0,出錯則返回- 1。signo是指定信號的編號。若act指針非空,則根據act修改該信號的處理動作。若oact指針非 空,則通過oact傳出該信號原來的處理動作。act和oact指向sigaction結構體:

將sa_handler賦值為常數SIG_IGN傳給sigaction表示忽略信號,賦值為常數SIG_DFL表示執行系統默認動作,賦值為一個函數指針表示用自定義函數捕捉信號,或者說向內核注冊了一個信號處理函 數,該函數返回值為void,可以帶一個int參數,通過參數可以得知當前信號的編號,這樣就可以用同一個函數處理多種信號。顯然,這也是一個回調函數,不是被main函數調用,而是被系統所調用。

當某個信號的處理函數被調用時,內核自動將當前信號加入進程的信號屏蔽字,當信號處理函數返回時自動恢復原來的信號屏蔽字,這樣就保證了在處理某個信號時,如果這種信號再次產生,那么 它會被阻塞到當前處理結束為止。 如果在調用信號處理函數時,除了當前信號被自動屏蔽之外,還希望自動屏蔽另外一些信號,則用sa_mask字段說明這些需要額外屏蔽的信號,當信號處理函數返回時自動恢復原來的信號屏蔽字。

可重入函數

main函數調用insert函數向一個鏈表head中插入節點node1,插入操作分為兩步,剛做完第一步的 時候,因為硬件中斷使進程切換到內核,再次回用戶態之前檢查到有信號待處理,于是切換 到sighandler函數,sighandler也調用insert函數向同一個鏈表head中插入節點node2,插入操作的 兩步都做完之后從sighandler返回內核態,再次回到用戶態就從main函數調用的insert函數中繼續 往下執行,先前做第一步之后被打斷,現在繼續做完第二步。結果是,main函數和sighandler先后 向鏈表中插入兩個節點,而最后只有一個節點真正插入鏈表中了。?

像上例這樣,insert函數被不同的控制流程調用,有可能在第一次調用還沒返回時就再次進入該函數,這稱為重入,insert函數訪問一個全局鏈表,有可能因為重入而造成錯亂,像這樣的函數稱為 不可重入函數,反之,如果一個函數只訪問自己的局部變量或參數,則稱為可重入(Reentrant) 函數。

如果一個函數符合以下條件之一則是不可重入的:

  • 調用了malloc或free,因為malloc也是用全局鏈表來管理堆的。
  • 調用了標準I/O庫函數。標準I/O庫的很多實現都以不可重入的方式使用全局數據結構。

volatile

先看一段代碼:

#include<iostream>2 #include<signal.h>3 #include<unistd.h>4 #include<cstdio>5 using namespace std;6 volatile int flag = 0;                                           
W>  7 void handler(int sig)8 {9     cout<<"flah is chenged:0 to 1"<<endl;10     flag = 1;11 }12 int main()13 {14     signal(2, handler);15     while(!flag);16     printf("process quit normal\n");17     return 0;}

正常情況下程序運行起來當我們使用鍵盤ctrl+c后操作系統會給進程發送信號,執行我們的自定義方法,flag值發生變化;打印語句程序退出。

優化情況下,鍵入 CTRL-C ,2號信號被捕捉,執行自定義動作,修改 flag=1 ,但是 while 條件依舊滿足,進程繼續運行!但是很明顯flag肯定已經被修改了,但是為何循環依舊執行?很明顯, while 循環檢查的flag,并不是內存中最新的flag,這就存在了數據二異性的問題。 while 檢測的flag其實已經因為優化,被放在了CPU寄存器當中。

對于這種情況我們可以使用volatile關鍵字:保持內存的可見性,告知編譯器,被該關鍵字修飾的變量,不允許被優化,對該變量的任何操作,都必須在真實的內存中進行操作。


今天對Linux下信號的保存的分享到這就結束了,希望大家讀完后有很大的收獲,也可以在評論區點評文章中的內容和分享自己的看法;個人主頁還有很多精彩的內容。您三連的支持就是我前進的動力,感謝大家的支持!!!

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

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

相關文章

c++算法入門教程(2)

C是一種功能強大且廣泛應用的編程語言&#xff0c;對于想要深入學習編程和算法的人來說&#xff0c;掌握C是一個重要的里程碑。本文將帶你逐步了解C編程的基礎知識&#xff0c;并介紹一些常見的算法和編程技巧幫你入門c算法。 ?在c算法入門教程(1) 中&#xff0c;我講解了什么…

GEE:使用Sigmoid激活函數對單波段圖像進行變換(以NDVI為例)

作者:CSDN @ _養樂多_ 本文將介紹在 Google Earth Engine (GEE)平臺上,對任意單波段影像進行 Sigmoid 變換的代碼。并以對 NDVI 影像像素值的變換為例。 文章目錄 一、Sigmoid激活函數1.1 什么是 Sigmoid 激活函數1.2 用到遙感圖像上有什么用?二、代碼鏈接三、完整代碼一…

查詢每個會話使用內存大小(DM8達夢數據庫)

DM8達夢數據庫查詢每個會話使用內存大小 1 環境介紹2 查詢每個sql會話使用內存大小3 達夢數據庫學習使用列表 1 環境介紹 在某些環境數據庫內存增長到服務器內存用完,發生OOM事件,可以分析sql會話使用內存大小; 2 查詢每個sql會話使用內存大小 --創建SQL會話占用內存記錄表 …

共享棧的C語言實現

共享棧&#xff1a;所謂共享棧就是為了節省空間&#xff0c;讓兩個棧共享一片連續的存儲空間&#xff0c;兩個棧從這片連續的共享空間的兩端向中間擴充自己的存儲空間&#xff0c;設這片存儲空間的大小為maxSize&#xff0c;采用棧頂指針始終指向當前棧頂元素的方式來實現共享棧…

簡單認識算法的復雜度

時間復雜度與空間復雜度 1.算法的復雜度 ? 算法在編寫成可執行程序后&#xff0c;運行時需要耗費時間資源和空間(內存)資源 。因此衡量一個算法的好壞&#xff0c;一般是從時間和空間兩個維度來衡量的&#xff0c;即時間復雜度和空間復雜度。 ? 時間復雜度主要衡量一個算法…

MYSQL02高級_目錄結構、默認數據庫、表文件、系統獨立表空間

文章目錄 ①. MySQL目錄結構②. 查看默認數據庫③. MYSQL5.7和8表文件③. 系統、獨立表空間 ①. MySQL目錄結構 ①. 如何查看關聯mysql目錄 [rootmysql8 ~]# find / -name mysql /var/lib/mysql /var/lib/mysql/mysql /etc/selinux/targeted/tmp/modules/100/mysql /etc/seli…

前端src中圖片img標簽資源的幾種寫法?

在 Vue 項目中引用圖片路徑有幾種不同的方法&#xff0c;具體取決于你的項目結構和配置。以下是幾種常見的方式&#xff1a; 1. 靜態資源目錄 (Public) 如果你的圖片放在了項目的 public 目錄下&#xff08;例如&#xff0c;Vite 和 Create Vue App 腳手架工具通常使用這個目…

05 OpenCV圖像混合技術

文章目錄 理論算子示例 理論 其中 的取值范圍為0~1之間 算子 addWeighted CV_EXPORTS_W void addWeighted(InputArray src1, double alpha, InputArray src2, double beta,double gamma, OutputArray dst, int dtype -1 ); 參數1&#xff1a;輸入圖像Mat …

2024年【廣東省安全員A證第四批(主要負責人)】考試試卷及廣東省安全員A證第四批(主要負責人)作業模擬考試

題庫來源&#xff1a;安全生產模擬考試一點通公眾號小程序 廣東省安全員A證第四批&#xff08;主要負責人&#xff09;考試試卷根據新廣東省安全員A證第四批&#xff08;主要負責人&#xff09;考試大綱要求&#xff0c;安全生產模擬考試一點通將廣東省安全員A證第四批&#x…

釘釘機器人發送折線圖卡片 工具類代碼

釘釘機器人 “創建并投放卡片 接口 ” 可以 發送折線圖、柱狀圖 官方文檔&#xff1a;創建并投放卡片 - 釘釘開放平臺 0依賴、1模板、2機器人放到內部應用、3放開這個權限 、4工具類、5調用工具類 拼接入參 卡片模板 自己看文檔創建&#xff0c;卡片模板的id 有用 0、依賴…

Springboot項目中定時任務的四種實現方式

文章目錄 1. 使用Scheduled注解1.1 時間間隔執行1.2 固定時間點執行 2. 使用EnableScheduling注解啟用定時任務3. 實現SchedulingConfigurer接口4. 使用Quartz框架4.1 配置QuartzScheduler4.2 定義Job類和Trigger類 5. 總結 在開發現代應用時&#xff0c;定時任務是一個非常常見…

地圖可視化繪制 | R-ggplot2 NC地圖文件可視化

在推出兩期數據分享之后&#xff0c;獲取數據的小伙伴們也知道&#xff0c;數據格式都是NetCDF(nc) 格式網格數據&#xff0c;雖然我在推文分享中說明使用Python、R或者GIS類軟件都是可以進行 處理和可視化繪制的&#xff0c;但是&#xff0c;還是有小伙伴咨詢使用編程軟件Pyth…

牛客周賽 Round 34(A,B,C,D,E,F,G)

把這場忘了。。官方也遲遲不發題解 比賽鏈接 出題人題解 A 小紅的字符串生成 思路&#xff1a; 枚舉四種字符串打印出來即可&#xff0c;為了防止重復可以用set先去一下重。 code&#xff1a; #include <iostream> #include <cstdio> #include <cstring&g…

Opencv實戰(4)詳解輪廓

輪廓 Opencv實戰系列&#xff0c;前文&#xff1a; 文章目錄 輪廓(1).查找繪制1.findContours()2.drawContours() (2).層級結構(3).篩選輪廓(4).凸包 (1).查找繪制 預處理&#xff1a; 灰度化&#xff1a;使用cv::cvtColor()圖像去噪&#xff1a;使用高斯濾波cv::Gaussian(…

Acwing-基礎算法課筆記之數學知識(擴展歐幾里得算法)

Acwing-基礎算法課筆記之數學知識&#xff08;擴展歐幾里得算法&#xff09; 一、擴展歐幾里得算法1、裴蜀定理2、過程模擬3、代碼模板 二、線性同余方程1、定義2、模擬過程3、結論證明 一、擴展歐幾里得算法 1、裴蜀定理 對于任意正整數 a a a&#xff0c; b b b&#xff0…

day48 ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

一遍過。 當前房屋偷與不偷取決于 前一個房屋和前兩個房屋是否被偷了。所以這里就更感覺到&#xff0c;當前狀態和前面狀態會有一種依賴關系&#xff0c;那么這種依賴關系都是動規的遞推公式。 class Solution { public:int rob(vector<int>& nums) {vector<vec…

門店縱深不足、入口有遮擋影響客流準確率?近景客流幫你搞定!

為了優化運營策略、提升門店營收&#xff0c;很多店鋪和商場都會安裝客流攝像機。但是在實際應用中&#xff0c;由于門店縱深受限等原因&#xff0c;導致無法使用之前的常規客流產品。 針對這種情況&#xff0c;悠絡客最新研發了近景客流產品&#xff0c;即使存在入口被遮擋或門…

內網信息搜集

目錄 內網基礎知識 基本流程圖 怎么判斷是否在域內 常規信息類收集-應用&服務&權限等 cs信息搜集 bloodhound安裝及使用 內網基礎知識 工作組&#xff1a;將不同的計算機按照功能分別列入不同的組&#xff0c;想要訪問某個部門的資源&#xff0c;只要在【網絡】里…

pyqt教程

一、組件安裝配置 1.安裝組件 在Anaconda Prompt下進入自己的python環境 pip install PyQt5 pip install PyQt5-tools 2.vscode安裝插件 3.配置路徑 配置Pyuic:Cmd與Qtdesigner:Path路徑 1.Pyuic:Cmd路徑 一般是在你安裝的python環境下的 \Scripts\pyuic5.exe 2.Qtdesigner:P…

anaconda簡介以及安裝(Windows)

介紹 Anaconda是一個開源的Python發行版本&#xff0c;它是一個打包的集合&#xff0c;里面預裝了conda、Python、眾多packages、科學計算工具等。Anaconda的目的是方便使用Python進行數據科學研究&#xff0c;它涵蓋了數據科學領域常見的Python庫&#xff0c;并且自帶了專門用…