Linux:進程信號---信號的保存與處理

文章目錄

      • 1. 信號的保存
        • 1.1 信號的狀態管理
      • 2. 信號的處理
        • 2.1 用戶態與內核態
        • 2.2 信號處理和捕捉的內核原理
        • 2.3 sigaction函數
      • 3. 可重入函數
      • 4. Volatile
      • 5. SIGCHLD信號

  • 序:在上一章中,我們對信號的概念及其識別的底層原理有了一定認識,也知道了信號產生的五種方式,以及core dump是什么,而本章將著重對信號的保存與處理進行講解,去深入了解信號處理的底層邏輯,去了解什么是用戶態和內核態,以及用戶態和內核態轉換的時機,本章還會淺談可重入函數以及Volatile關鍵字

1. 信號的保存

1.1 信號的狀態管理

對于普通信號而言,對于進程(是給進程的PCB發)而言,要識別自己有沒有收到信號,以及收到了哪一個信號。

task_struct{
int signal;// 0000 ...... 0000普通信號,位圖管理信號
}

1. 比特位的內容是0還是1,表明是否收到
2. 比特位的位置(第幾個),表明信號的編號
3. 所謂的 “發信號” ,本質就是操作系統去修改task_struct的信號位圖對應的比特位(寫信號!!!)

問題一:信號為什么要保存?

進程收到信號之后,可能不會立即處理這個信號。此時信號不會被處理,就要有一個時間窗口。信號的范圍[1,31],每一種信號都要有自己的一種處理方法.

信號的幾種狀態:

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

信號在內核中的表示示意圖:
在這里插入圖片描述

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

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

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

sigpending函數:
在這里插入圖片描述

其中的set參數是一個輸出型參數,他會將當前的pending表傳出。

sigprocmask函數:
在這里插入圖片描述

第一個參數how:

參數含義
SIG_BLOCKset包含了我們希望添加到當前信號屏蔽字的信號
SIG_UNBLOCKset包含了我們希望從當前信號屏蔽字中解除阻塞的信號
SIG_SETMASK設置當前信號屏蔽字為set所指向的值

第二個參數:表示要傳入的block阻塞表
第三個參數:表示之前的block舊表

問題二:我要是將所以信號都進行屏蔽,信號不就不會被處理了嗎?

然而操作系統不會給你這個機會的,比如9號信號和19號信號,用戶就屏蔽不了

2. 信號的處理

2.1 用戶態與內核態

問題一:信號是什么時候被處理的?

當我們的進程從內核態返回到用戶態的時候,進行信號好的檢測和處理

當我們在調用系統調用時,操作系統會將我們的用戶身份轉化為內核身份,然后由操作系統幫我把函數執行完,返回時,再把我的內核身份換回用戶身份 ------ 操作系統是自動會做“身份”切換的,用戶身份變成內核身份,或者反著來!

問題二:什么是用戶態和內核態?

內核態:允許你訪問操作系統的代碼和數據
用戶態:只能訪問用戶自己的代碼和數據

2.2 信號處理和捕捉的內核原理

問題三:信號是如何被處理的?

在這里插入圖片描述

操作系統不信任用戶,不僅僅體現在不讓用戶訪問自己,也體現在操作系統不會訪問用戶自己寫的代碼!!!所以當在內核態處理信號時,會先將該信號的pending置0,然后去執行,要是執行到了自定義行為,那么進程就要先由內核狀態轉化為用戶態,去執行這個自定義行為,然后再變為內核態繼續在操作系統中執行系統操作,然后再回到用戶態,返回值。(基于用戶捕捉代碼)

問題四:內核如何實現信號的捕捉

在這里插入圖片描述

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

在這里插入圖片描述

在這個過程中,一共發生了四次狀態的轉換,所謂的信號的識別,其實就是在進程進入內核態時,順手完成的任務。CPU內部的信號int 80(是一條匯編語句) 從用戶態陷入內核態,這樣就有權利去訪問操作系統的數據了。

2.3 sigaction函數

sigaction函數:
在這里插入圖片描述

sigaction結構體:

struct sigaction {void     (*sa_handler)(int);void     (*sa_sigaction)(int, siginfo_t *, void *);sigset_t   sa_mask;int        sa_flags;void     (*sa_restorer)(void);};

由于我們目前只研究普通信號,所以,該結構體當中的第二、第四和第五個參數我們不做討論,感興趣的小伙伴可以自行去搜索。
該函數的第一個參數是要處理的信號數字,第二個參數表示要傳入的sigaction結構體,第三個參數是輸出型參數,他會保存上一次的sigaction結構體的數據。

直觀的代碼和運行結果能讓我們直接看到這個函數的作用:

#include<iostream>
#include<cstring>
#include<signal.h>
#include<unistd.h>using namespace std;void PrintPending()
{sigset_t myset;sigpending(&myset);for(int signo=31;signo>=1;signo--){if(sigismember(&myset,signo)){cout<<"1";}else{cout<<"0";}}cout<<endl;
}void handler(int signo)
{while(true){PrintPending();cout<<"signal : "<<signo<<" acted"<<endl;sleep(1);}
}int main()
{signal(SIGINT,handler);struct sigaction myset,oset;memset(&myset,0,sizeof(myset));memset(&myset,0,sizeof(oset));//sigemptyset(&myset.sa_mask);//sigaddset(&myset.sa_mask,SIGINT);myset.sa_handler=handler;sigaction(SIGINT,&myset,&oset);while(true){cout<<"i am process: "<<getpid()<<endl;sleep(1);}return 0;
}

運行結果如下:
在這里插入圖片描述

由上圖可知,在處理某個信號之前,該信號的pending表對應的值會先置0,然后才會執行對應的處理行動。

總結:如果某個信號正在進行處理,那么,在這個期間,這個信號的信號屏蔽字將會變成1,此時,無論外界再發送多少個該信號,都不會執行,只會將該信號對應的pending表中的值置1,但是不是執行,因為此時該信號已經阻塞了,這就防止了當該信號處理時,被重復執行,之后當這個信號處理完畢,才會取消阻塞,然后繼續執行之前發的信號,并在信號執行期間繼續阻塞該信號!!!

3. 可重入函數

在這里插入圖片描述

當我們執行insert函數時,進行到一半,執行完p->next=head;語句后,觸發了信號,執行此時信號中也有insert函數,然后執行信號中的insert,執行信號處理后,再繼續執行main函數中的語句head=p;此時,由于函數重入,引發節點丟失,導致內存泄漏!!!

如果一個函數,被重復進入的情況下,出錯了,或者可能出錯,就叫做不可重入函數。否則就叫做可重入函數。

4. Volatile

在這里插入圖片描述

在g++中是有優化選項的,編譯器在編譯的時候,有不同的優化級別

源代碼:

#include<iostream>
#include<cstring>
#include<signal.h>
#include<unistd.h>using namespace std;int flag=0;void handler(int signo)
{cout<<" change flag 0->1 "<<endl;flag=1;
}int main()
{signal(SIGINT,handler);while(!flag);cout<<"process quit"<<endl;return 0;
}

1. O0的優化:

sigproc:sigproc.cppg++ -o $@ $^ -O1 -g -std=c++11

結果如圖:
在這里插入圖片描述

2. O1的優化:

sigproc:sigproc.cppg++ -o $@ $^ -O1 -g -std=c++11

結果如圖:
在這里插入圖片描述

3. O3的優化:

sigproc:sigproc.cppg++ -o $@ $^ -O3 -g -std=c++11

結果如圖:
在這里插入圖片描述

問題一:為什么優化過后,程序退不出去?

在這里插入圖片描述
此時volatile int flag=0;使用volatile關鍵字修飾flag就能防止編譯器過度優化,保持內存的可見性!!!

5. SIGCHLD信號

當子進程退出時,不是靜悄悄的退出,子進程在退出的時候,會主動向父進程發送SIGCHLD(17號)信號。所以在進行進程等待的時候,我們可以采用基于信號的方式進行等待

問題一:等待的好處是什么?

1. 獲取子進程的退出狀態,釋放子進程的僵尸。
2. 雖然不知道父子進程誰先運行(由調度器決定),但是我們清楚,一定是父進程先退出!!!
所以,還是要調用wait/waitpid這樣的接口,且父進程必須保證自己是一直在運行的!

問題二:我們必須等待嗎?必須調用wait嗎?

Signal(17,SIG_IGN);表示忽略17號信號,子進程會自動退出!!!

總結:

本章帶大家理解了信號的保存與處理,知道了信號的不同的保存狀態,以及處理信號時的內核態和用戶態的轉化原理,還擴展了可重入函數和Volatile關鍵字,以及SIGCHLD信號,最后,希望這篇文章對大家有一定幫助。

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

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

相關文章

UML 圖的細分類別及其應用

統一建模語言&#xff08;UML&#xff0c;Unified Modeling Language&#xff09;是一種用于軟件系統建模的標準化語言&#xff0c;廣泛應用于軟件工程領域。UML 圖分為多種類別&#xff0c;每種圖都有其特定的用途和特點。本文將詳細介紹 UML 圖的細分類別&#xff0c;包括 類…

「極簡」扣子(coze)教程 | 小程序UI設計進階!控件可見性設置

大師兄在上一期的內容中對用戶的UI做了一些簡單的介紹。這期大師兄繼續介紹UI設計上的進階小技巧&#xff0c;幫我們獲得更好的使用體驗。 扣子&#xff08;coze&#xff09;編程 「極簡」扣子(coze)教程 | 3分鐘學會小程序UI設計&#xff01;從零開始創建頁面和瓷片按鈕 「極…

2025年滲透測試面試題總結-快手[實習]安全工程師(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 快手[實習]安全工程師 一面問題分析與詳細回答 1. 自我介紹 4. 項目問題與解決 7. 防止SQL注入&…

WordPress Madara插件存在文件包含漏洞(CVE-2025-4524)

免責聲明 本文檔所述漏洞詳情及復現方法僅限用于合法授權的安全研究和學術教育用途。任何個人或組織不得利用本文內容從事未經許可的滲透測試、網絡攻擊或其他違法行為。使用者應確保其行為符合相關法律法規,并取得目標系統的明確授權。 對于因不當使用本文信息而造成的任何直…

互聯網大廠Java面試場景:從Spring Boot到分布式緩存技術的探討

互聯網大廠Java面試場景&#xff1a;從Spring Boot到分布式緩存技術的探討 場景描述 互聯網大廠某次Java開發崗面試&#xff0c;主考官是一位嚴肅的技術專家&#xff0c;而應聘者則是搞笑的程序員“碼農明哥”。面試圍繞音視頻場景的技術解決方案展開&#xff0c;探討從Sprin…

leetcode hot100刷題日記——8.合并區間

class Solution { public:vector<vector<int>> merge(vector<vector<int>>& intervals) {if(intervals.empty()){//復習empty函數啊&#xff0c;日記1有的return {};}// 按照區間的起始位置進行排序sort(intervals.begin(), intervals.end());vect…

Unity中GPU Instancing使用整理

GPU Instancing是一種繪制調用優化方法,可在單個繪制調用中渲染具有相同材質Mesh的多個副本(實例),可用于繪制在場景中多次出現的幾何體(例如,樹木或灌木叢),在同一繪制調用中渲染相同的網格,每個實例可以具有不同的屬性(如 Color 或 Scale),渲染多個實例的繪制調用…

【后端】【UV】【Django】 `uv` 管理的項目中搭建一個 Django 項目

&#x1f680; 一步步搭建 Django 項目&#xff08;適用于 uv pyproject.toml 項目結構&#xff09; &#x1f9f1; 第 1 步&#xff1a;初始化一個 uv 項目&#xff08;如果還沒建好&#xff09; uv init django-project # 創建項目&#xff0c;類似npm create vue?? 第 …

Linux操作系統之進程(二):進程狀態

目錄 前言 一、補充知識點 1、并行與并發 2、時間片 3、 等待的本質 4、掛起 二. 進程的基本狀態 三、代碼演示 1、R與S 2、T 3、Z 四、孤兒進程 總結&#xff1a; 前言 在操作系統中&#xff0c;進程是程序執行的基本單位。每個進程都有自己的狀態&#xff0c;這些…

大數據技術全景解析:HDFS、HBase、MapReduce 與 Chukwa

大數據技術全景解析&#xff1a;HDFS、HBase、MapReduce 與 Chukwa 在當今這個信息爆炸的時代&#xff0c;大數據已經成為企業競爭力的重要組成部分。從電商的用戶行為分析到金融的風險控制&#xff0c;從醫療健康的數據挖掘到智能制造的實時監控&#xff0c;大數據技術無處不…

學習 Android(十一)Service

簡介 在 Android 中&#xff0c;Service 是一種無界面的組件&#xff0c;用于在后臺執行長期運行或跨進程的任務&#xff0c;如播放音樂、網絡下載或與遠程服務通信 。Service 可分為“啟動型&#xff08;Started&#xff09;”和“綁定型&#xff08;Bound&#xff09;”兩大…

投標環節:如何科學、合理地介紹 Elasticsearch 國產化替代方案——Easysearch?

一、Easysearch 定義 Easysearch 是由極限科技&#xff08;INFINI Labs&#xff09;自主研發的分布式搜索型數據庫&#xff0c;作為 Elasticsearch 的國產化替代方案&#xff0c;基于 Elasticsearch 7.10.2 開源版本深度優化[1]。 插一句&#xff1a;Elasticsearch 7.10.2 是里…

NVC++ 介紹與使用指南

文章目錄 NVC 介紹與使用指南NVC 簡介安裝 NVC基本使用編譯純 C 程序編譯 CUDA C 程序 關鍵編譯選項示例代碼使用標準并行算法 (STDPAR)混合 CUDA 和 C 優勢與限制優勢限制 調試與優化 NVC 介紹與使用指南 NVC 是 NVIDIA 提供的基于 LLVM 的 C 編譯器&#xff0c;專為 GPU 加速…

Veo 3 可以生成視頻,并附帶配樂

谷歌最新的視頻生成 AI 模型 Veo 3 可以創建與其生成的剪輯相配的音頻。 周二&#xff0c;在谷歌 I/O 2025 開發者大會上&#xff0c;谷歌發布了 Veo 3。該公司聲稱&#xff0c;這款產品可以生成音效、背景噪音&#xff0c;甚至對話&#xff0c;為其制作的視頻增添配樂。谷歌表…

Android本地語音識別引擎深度對比與集成指南:Vosk vs SherpaOnnx

技術選型對比矩陣 對比維度VoskSherpaOnnx核心架構基于Kaldi二次開發ONNX Runtime + K2新一代架構模型格式專用格式(需專用工具轉換)ONNX標準格式(跨框架通用)中文識別精度89.2% (TDNN模型)92.7% (Zipformer流式模型)內存占用60-150MB30-80MB遲表現320-500ms180-300ms多線程…

十四、Hive 視圖 Lateral View

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月20日 專欄&#xff1a;Hive教程 在Hive中&#xff0c;我們經常需要以不同于原始表結構的方式查看或處理數據。為了簡化復雜查詢、提供數據抽象&#xff0c;以及處理復雜數據類型&#xff08;如數組或Map&#xff09;&#…

微軟開源GraphRAG的使用教程-使用自定義數據測試GraphRAG

微軟在今年4月份的時候提出了GraphRAG的概念,然后在上周開源了GraphRAG,Github鏈接見https://github.com/microsoft/graphrag,截止當前,已有6900+Star。 安裝教程 官方推薦使用Python3.10-3.12版本,我使用Python3.10版本安裝時,在初始化項目過程中會報錯,切換到Python3.…

XXX企業云桌面系統建設技術方案書——基于超融合架構的安全高效云辦公平臺設計與實施

目錄 1. 項目背景與目標1.1 背景分析1.2 建設目標2. 需求分析2.1 功能需求用戶規模與場景終端兼容性2.2 非功能需求3. 系統架構設計3.1 總體架構圖流程圖說明3.2 技術選型對比3.3 網絡設計帶寬規劃公式4. 詳細實施方案4.1 分階段部署計劃4.2 桌面模板配置4.3 測試方案性能測試工…

數據直觀分析與可視化

數據直觀分析與可視化 一、數據的直觀分析核心價值 數據的直觀分析旨在通過視覺化的方式&#xff0c;幫助人們更直觀、更快速地理解數據的特征和模式&#xff0c;從而發現趨勢、異常值、分布情況以及變量之間的關系&#xff0c;為決策提供支持。 數據可視化與信息圖形、信息可…

Neo4j數據庫

Neo4j 是一款專門用來處理復雜關系的數據庫。我們可以簡單地將它理解為一個“用圖結構來管理數據的工具”。與我們常見的&#xff0c;像 Excel 那樣用表格&#xff08;行和列&#xff09;來存儲數據的傳統數據庫不同&#xff0c;Neo4j 采用了一種更接近人類思維對現實世界理解的…