Linux信號機制:從入門到精通

嘿,小伙伴們!今天我要和大家聊一個Linux系統中非常有趣又重要的話題——信號機制。別擔心,雖然信號聽起來有點高深,但我會用最通俗易懂的語言,配合清晰的圖表,帶你徹底搞懂這個概念!

什么是信號?

想象一下,如果你正在專心寫代碼,突然有人拍了一下你的肩膀,這就類似于操作系統中的"信號"。信號是Linux系統中用于通知進程發生了某種事件的一種異步通信機制,就像操作系統給進程發送的"緊急短信"。

信號的本質是軟件中斷,當進程收到信號后,會暫停當前工作,轉而去處理這個信號,處理完后再回到原來的工作。這就像你接到一個緊急電話,處理完緊急事務后再回到之前的工作一樣。

為什么需要信號?

在Linux系統中,信號主要用于以下幾個場景:

  1. 錯誤處理:當程序出現嚴重錯誤(如除零、非法內存訪問)時,系統會發送相應信號
  2. 終止進程:用戶可以通過按下Ctrl+C發送SIGINT信號來終止前臺進程
  3. 進程間通信:一個進程可以通過信號通知另一個進程發生了某事
  4. 定時器功能:通過SIGALRM信號實現定時器功能
  5. 狀態變化通知:如子進程終止時,父進程會收到SIGCHLD信號

Linux信號的種類

Linux系統定義了多種信號,每種信號都有特定的用途。以下是一些常見的信號:

信號名稱信號值默認動作描述
SIGHUP1終止終端斷開連接
SIGINT2終止鍵盤中斷(Ctrl+C)
SIGQUIT3終止 + core鍵盤退出(Ctrl+\)
SIGILL4終止 + core非法指令
SIGTRAP5終止 + core斷點陷阱
SIGABRT6終止 + core調用 abort 函數
SIGFPE8終止 + core浮點異常
SIGKILL9終止強制終止(不可捕獲)
SIGSEGV11終止 + core段錯誤(無效內存引用)
SIGPIPE13終止管道破裂
SIGALRM14終止定時器到期
SIGTERM15終止終止信號(kill 命令默認)
SIGUSR110終止用戶自定義信號 1
SIGUSR212終止用戶自定義信號 2
SIGCHLD17忽略子進程狀態改變
SIGCONT18繼續繼續執行被停止的進程
SIGSTOP19停止停止進程(不可捕獲)
SIGTSTP20停止鍵盤停止(Ctrl+Z)

信號的生命周期

信號的生命周期包括三個階段:產生、未決和處理。

1. 信號的產生

信號可以通過多種方式產生:

2. 信號的未決狀態

當信號產生后,會進入未決狀態,等待被處理。如果此時該信號被阻塞(blocked),則會保持未決狀態,直到解除阻塞。

3.?信號的處理

當信號遞達(delivered)到進程后,進程會根據信號處理方式來響應:

  • 默認處理:每個信號都有默認動作,如終止進程、忽略信號等
  • 忽略信號:進程可以選擇忽略某些信號(但SIGKILL和SIGSTOP不能被忽略)
  • 捕獲信號:進程可以注冊自定義的信號處理函數

信號處理的編程實踐

注冊信號處理函數

在C/C++中,我們可以使用signal()或更強大的sigaction()函數來注冊信號處理函數:

#include?<signal.h>//?信號處理函數void?signal_handler(int?signum)?{printf("捕獲到信號?%d\n",?signum);//?處理信號的代碼}int?main()?{//?注冊SIGINT信號的處理函數signal(SIGINT,?signal_handler);//?程序主循環while(1)?{printf("程序運行中...\n");sleep(1);}return?0;}

使用sigaction()函數(推薦)

sigaction()比signal()更強大,提供了更多控制選項:

#include?<signal.h>void?signal_handler(int?signum)?{printf("捕獲到信號?%d\n",?signum);}int?main()?{struct?sigaction?sa;sa.sa_handler?=?signal_handler;sigemptyset(&sa.sa_mask);??//?清空信號集sa.sa_flags?=?0;//?注冊SIGINT信號的處理函數sigaction(SIGINT,?&sa,?NULL);while(1)?{printf("程序運行中...\n");sleep(1);}return?0;}

發送信號

進程可以使用kill()函數向其他進程發送信號:

#include?<signal.h>#include?<sys/types.h>int?main()?{pid_t?pid?=?1234;??//?目標進程ID//?向進程發送SIGTERM信號kill(pid,?SIGTERM);return?0;}

信號傳遞流程圖:

信號集操作

信號集是一組信號的集合,可以用來表示要阻塞的信號。Linux提供了一系列函數來操作信號集:

#include?<signal.h>int?main()?{sigset_t?set;//?初始化信號集sigemptyset(&set);??//?清空信號集//?添加信號到集合sigaddset(&set,?SIGINT);sigaddset(&set,?SIGTERM);//?阻塞這些信號sigprocmask(SIG_BLOCK,?&set,?NULL);//?...?執行不想被這些信號打斷的代碼?...//?解除阻塞sigprocmask(SIG_UNBLOCK,?&set,?NULL);return?0;}

實際應用場景

1. 優雅地退出程序

當用戶按下Ctrl+C時,我們可能需要先清理資源再退出:

#include?<signal.h>#include?<stdio.h>#include?<stdlib.h>#include?<unistd.h>volatile?sig_atomic_t?keep_running?=?1;void?cleanup_and_exit()?{printf("清理資源...\n");//?關閉文件、釋放內存等清理操作printf("清理完成,退出程序\n");}void?handle_sigint(int?sig)?{printf("\n捕獲到SIGINT信號\n");keep_running?=?0;}int?main()?{struct?sigaction?sa;sa.sa_handler?=?handle_sigint;sigemptyset(&sa.sa_mask);sa.sa_flags?=?0;sigaction(SIGINT,?&sa,?NULL);printf("程序開始運行,按Ctrl+C退出\n");while?(keep_running)?{printf("工作中...\n");sleep(1);}cleanup_and_exit();return?0;}

2.?父進程監控子進程

父進程可以通過SIGCHLD信號來監控子進程的狀態變化:

#include?<signal.h>#include?<stdio.h>#include?<stdlib.h>#include?<sys/types.h>#include?<sys/wait.h>#include?<unistd.h>void?handle_sigchld(int?sig)?{int?status;pid_t?pid;//?非阻塞方式等待任何子進程while?((pid?=?waitpid(-1,?&status,?WNOHANG))?>?0)?{if?(WIFEXITED(status))?{printf("子進程?%d?正常退出,退出碼:?%d\n",?pid,?WEXITSTATUS(status));}?else?if?(WIFSIGNALED(status))?{printf("子進程?%d?被信號?%d?終止\n",?pid,?WTERMSIG(status));}}}int?main()?{struct?sigaction?sa;sa.sa_handler?=?handle_sigchld;sigemptyset(&sa.sa_mask);sa.sa_flags?=?SA_RESTART;sigaction(SIGCHLD,?&sa,?NULL);//?創建子進程pid_t?pid?=?fork();if?(pid?<?0)?{perror("fork");exit(1);}?else?if?(pid?==?0)?{//?子進程printf("子進程?%d?開始運行\n",?getpid());sleep(2);printf("子進程?%d?結束運行\n",?getpid());exit(42);}?else?{//?父進程printf("父進程?%d?創建了子進程?%d\n",?getpid(),?pid);//?父進程繼續執行其他工作for?(int?i?=?0;?i?<?5;?i++)?{printf("父進程工作中...\n");sleep(1);}}return?0;}

3. 使用定時器

通過SIGALRM信號實現定時功能:

#include?<signal.h>#include?<stdio.h>#include?<unistd.h>void?handle_alarm(int?sig)?{printf("時間到!\n");}int?main()?{struct?sigaction?sa;sa.sa_handler?=?handle_alarm;sigemptyset(&sa.sa_mask);sa.sa_flags?=?0;sigaction(SIGALRM,?&sa,?NULL);printf("設置3秒定時器...\n");alarm(3);printf("等待定時器...\n");pause();??//?暫停直到收到信號printf("繼續執行\n");return?0;}

信號處理的注意事項

  1. 信號處理函數應該盡量簡單:因為信號處理函數可能在任何時候被調用,所以應該避免復雜操作。
  2. 不可重入函數:在信號處理函數中應避免調用不可重入函數(如malloc、printf等),可能導致不可預測的行為。
  3. 全局變量訪問:如果在信號處理函數和主程序之間共享變量,應聲明為volatile sig_atomic_t類型,確保原子訪問。
  4. SIGKILL和SIGSTOP:這兩個信號不能被捕獲、阻塞或忽略,始終執行默認動作。
  5. 信號丟失:如果同一信號多次發送,而進程還沒來得及處理,通常只會記錄一次,可能導致信號丟失。

信號與多線程

在多線程程序中,信號處理變得更加復雜:

  1. 信號會被發送到進程中的任一線程,由系統選擇
  2. 可以使用pthread_sigmask()函數來設置線程的信號掩碼
  3. 可以使用sigwait()函數來專門處理信號的線程
#include?<signal.h>#include?<pthread.h>#include?<stdio.h>#include?<unistd.h>void*?signal_thread(void*?arg)?{sigset_t*?set?=?(sigset_t*)arg;int?sig;while?(1)?{//?等待信號sigwait(set,?&sig);printf("收到信號?%d\n",?sig);if?(sig?==?SIGINT)?{printf("處理SIGINT信號\n");}?else?if?(sig?==?SIGTERM)?{printf("處理SIGTERM信號,準備退出\n");break;}}return?NULL;}int?main()?{sigset_t?set;pthread_t?thread;//?初始化信號集sigemptyset(&set);sigaddset(&set,?SIGINT);sigaddset(&set,?SIGTERM);//?在主線程中阻塞這些信號pthread_sigmask(SIG_BLOCK,?&set,?NULL);//?創建專門處理信號的線程pthread_create(&thread,?NULL,?signal_thread,?&set);printf("主線程運行中,按Ctrl+C發送SIGINT,kill?-15?%d發送SIGTERM\n",?getpid());//?主線程繼續工作while?(1)?{printf("主線程工作中...\n");sleep(1);}pthread_join(thread,?NULL);return?0;}

小結

信號是Linux系統中一種重要的進程間通信機制,雖然功能相對簡單(只能傳遞信號類型,不能傳遞額外數據),但在系統編程中有著廣泛的應用。掌握信號處理,對于編寫健壯的Linux程序至關重要。

信號機制看似簡單,實則暗藏玄機,特別是在多線程環境下。作為一名C++開發工程師,我建議大家在實際項目中謹慎使用信號,遵循最佳實踐,避免常見陷阱。

希望這篇文章能幫助你理解Linux信號機制!如果有問題,歡迎在評論區留言交流~


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

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

相關文章

Vue3項目引入高德地圖【超詳細教程】

前言 在 Vue 3 項目中集成高德地圖&#xff08;AMap&#xff09;是一個常見的需求。本文將詳細介紹如何在 Vue 3 項目中使用高德地圖&#xff0c;包括安裝配置、基本使用以及一些進階功能的實現。 一、環境準備 1.1 vue3項目初始化 步驟 1&#xff1a;初始化項目 npm crea…

blender mcp安裝(完全免費的ai建模)

1.最關鍵的一步&#xff0c;建議最早執行(就是安裝uvx) mac系統執行 brew install uvwindows執行 powershell -c "irm https://astral.sh/uv/install.ps1 | iex" 出現這一步就成功安裝uvx了&#xff0c;因為mcp需要使用uvx 2.第二步驟 github地址: https://gith…

GIS開發入門教程與筆記分享

大家好&#xff0c;我是地信小學生&#xff0c;距離5月3日發布暫停更新以來&#xff0c;也一兩個月啦&#xff0c;這期間也陸陸續續更新了點內容。 我自己寫的筆記主要是以入門筆記為主&#xff0c;真正的內容并不多&#xff0c;包括&#xff1a;GIS基礎、PostgreSQLPostGIS入門…

設計模式-代理模式、裝飾者模式

代理模式 Proxy&#xff08;代理&#xff09;—對象結構型模式定義&#xff1a;給某一個對象提供一個代理對象&#xff0c;并由代理對象控制原有對象的引用。 代理模式的核心思想是&#xff1a;創建一個代理對象&#xff0c;代理對象在調用目標方法時&#xff0c;可以插入額外…

國產安路FPGA純verilog視頻圖像去霧,基于暗通道先驗算法實現,提供5套TD工程源碼和技術支持

目錄 1、前言工程概述免責聲明 2、相關方案推薦我已有的所有工程源碼總目錄----方便你快速找到自己喜歡的項目國產安路FPGA相關方案推薦本博主已有的圖像處理方案 3、設計思路框架工程設計原理框圖輸入Sensor之-->GC0308攝像頭輸入Sensor之-->OV7725攝像頭輸入Sensor之--…

Windows商店中的簡筆畫學習應用

此應用包含動物、植物、人物、交通工具、卡通等類別超過1500張線條圖片&#xff0c;支持圖片臨摹和圖片填色&#xff0c;可以將繪圖和填色結果保存成文件&#xff0c;也可以打開本地圖片進行臨摹和填色。 菜單說明 右側繪圖區上方菜單功能包括&#xff1a;打開文件&#xff1…

樹莓派4B --ubundu20.04 機載電腦配置WIFI熱點

不要用刷機過程配置WIFI賬號&#xff0c;因為在那里配置的WIFI都是不受控的&#xff0c;會出很多問題。 1.安裝網絡 sudo apt-get install network-manager 2.將源碼CLONE到本地 sudo git clone https://github.com/oblique/create_ap cd create_ap sudo make install 當你…

??JETSON NANO B01? 在AIOT 的領域的作用

低功耗邊緣設備的理想選擇 &#x1f449; ??適合人群??&#xff1a;精打細算、小廠搞智能監控的 ??Jetson Nano B01??&#xff08;4GB內存/0.47TOPS算力&#xff09;&#xff0c;JetBot (NVIDIA社區版) 機器人/自動駕駛項目? ??硬件??&#xff1a;Jetson Nano B0…

Kioptrix Level2

靶機截圖 收集信息 主機發現 打開靶機后&#xff0c;用kali探測靶機的 IP arp-scan-l 可以用nmap進行同網段掃描探測存活ip nmap -sP 10.4.7.0/24 端口掃描 命令過程 nmap -sT -sV -p- -O 10.4.7.220 -sT&#xff1a;TCP連接掃描 -sV&#xff1a;服務版本探測 -p-&#x…

Word之電子章制作——1

第一步&#xff1a;在插入 ——形狀哪里選擇一個圓形&#xff0c;并且下一步按住shift鍵拉出一個正圓形。 第二步&#xff1a;鼠標右鍵去掉背景顏色&#xff0c;邊框粗細設置成3磅。 第三步&#xff1a;在插入導航窗找到藝術字&#xff0c;點擊大寫的A&#xff0c;輸入公司名字…

LeetCode 2799.統計完全子數組的數目

給你一個由 正 整數組成的數組 nums 。 如果數組中的某個子數組滿足下述條件&#xff0c;則稱之為 完全子數組 &#xff1a; 子數組中 不同 元素的數目等于整個數組不同元素的數目。 返回數組中 完全子數組 的數目。 子數組 是數組中的一個連續非空序列。 示例 1&#xff1…

33.表復制和去重

1.表結構的復制(LIKE) 當我們想復制一個表的時候&#xff0c;首先需要創建一個與被復制表相同結構的表。這時候就要用到關鍵字like&#xff1a; 語法使用&#xff1a; create table table_name LIKE temp_table 示例&#xff1a;復制一個和表emp&#xff08;老朋友了&#…

GitLab 18.1 正式發布Maven 虛擬倉庫、密碼泄露檢測等功能,可升級體驗!

GitLab 是一個全球知名的一體化 DevOps 平臺&#xff0c;很多人都通過私有化部署 GitLab 來進行源代碼托管。極狐GitLab 是 GitLab 在中國的發行版&#xff0c;專門為中國程序員服務。可以一鍵式部署極狐GitLab。 學習極狐GitLab 的相關資料&#xff1a; 極狐GitLab 官網極狐…

藍牙網絡拓撲面試通關:微微網與散射網原理 + 真題解析

為什么面試官總愛問藍牙拓撲? 你可能有過這樣的經歷:面試嵌入式 / 物聯網 / 無線通信崗位時,面試官突然問:“藍牙的微微網和散射網有什么區別?” 別慌!這不是在考你背定義,而是考察你對無線通信核心邏輯的理解 ——如何用有限資源實現高效組網。 藍牙作為短距離無線通信…

[Python]-基礎篇1- 從零開始的Python入門指南

無論你是尚未接觸編程的新手,還是想從其他語言轉向Python的開發者,這篇文章都是你的入門課。 一、Python是什么? Python是一種解釋型、高級、通用型編程語言,以簡潔明了、簡單易用著稱。它可以應用于網站開發、自動化腳本、數據分析、人工智能、系統操作等多種場景。 二、…

Objective-C面向對象編程:類、對象、方法詳解(保姆級教程)

目錄 一、核心概念 二、類的定義&#xff08;分.h和.m文件&#xff09; 1. 頭文件&#xff08;.h&#xff09;—— 公開聲明 2. 實現文件&#xff08;.m&#xff09;—— 具體實現 3. 屬性特性解析 原子性 所有權語義(ARC環境下) 讀寫控制 三、對象創建與內存管理 1…

CentOS 7 編譯ClickHouse 24.8完整指南

前言 在CentOS 7上編譯ClickHouse 24.8可能會遇到一些挑戰&#xff0c;主要是因為CentOS 7的默認軟件版本較舊。本文將詳細介紹從零開始構建ClickHouse 24.8的完整過程&#xff0c;包括依賴安裝和環境配置。 準備工作 首先確保系統已更新到最新版本&#xff1a; yum update…

Protocol Buffers (Protobuf) 全面解析

一、核心概念解析 1. 什么是數據序列化&#xff1f; #mermaid-svg-HZKw9iRlpQIRFiO3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-HZKw9iRlpQIRFiO3 .error-icon{fill:#552222;}#mermaid-svg-HZKw9iRlpQIRFiO3 .…

高斯混合模型GMMK均值(十三-1)——K均值是高斯混合模型的特例

EM算法與K均值算法的關系 K均值可以看成是高斯混合模型的特例。 對K均值算法與EM算法進行比較后&#xff0c;可以發現它們之間有很大的相似性。K均值算法將數據點硬&#xff08;hard&#xff09;分配到聚類中&#xff0c;每個數據點唯一地與一個聚類相關聯&#xff0c;而EM算法…

StarRocks 向量索引如何讓大模型“記性更好”?

隨著 ChatGPT、DeepSeek 等大語言模型的普及&#xff0c;我們已經能夠與 AI 進行流暢的對話。然而&#xff0c;即使是最先進的大模型也面臨著“記憶困境”&#xff0c;具體表現模型只能記住訓練時接觸的知識&#xff0c;且這些知識在使用時很可能會過期。實際應用或在處理特定領…