Linux系統編程—信號捕捉

2020-10-18 良許Linux

前面我們學習了信號產生的幾種方式,而對於信號的處理有如下幾種方式:

  1. 默認處理方式;
  2. 忽略;
  3. 捕捉。

信號的捕捉,說白了就是抓到一個信號後,執行我們指定的函數,或者執行我們指定的動作。下面詳細介紹兩個信號捕捉操作參數:signalsigaction

##signal函數

函數原型:

sighandler_t signal(int signum, sighandler_t handler);

其中,sighandler定義是這樣的:typedef void (*sighandler_t)(int);

函數作用:

註冊一個信號捕捉函數,也就是說,收到了某個信號,就執行它所註冊的回調函數。

函數參數:

signum:信號編號,儘量用宏來寫,而別用數字,這樣更適合跨平臺;

handler:註冊的回調函數;

函數缺陷:

由於歷史原因,該函數在不同版本的Unix和Linux系統中可能起到的效果不一樣,所以跨平臺性不佳,儘量避免使用它,取而代之使用通用性更好的sigaction函數。

#include <stdio.h> #include <signal.h> void func() { printf("SIGQUIT catched!\n"); } int main(){ signal(SIGQUIT, func); while(1);}

##sigaction函數

函數原型:

int sigaction(int signum, const struct sigaction act, struct sigaction oldact);

函數作用:

與signal函數類似,用來註冊一個信號捕捉函數;

返回值:

成功:0;失敗:-1,並設置errno;

參數:

signum:信號編號,儘量用宏來寫,而別用數字,這樣更適合跨平臺;

act:傳入參數,新的信號捕捉方式;

oldact:傳出參數,舊的信號捕捉方式

這裡特別要注意參數中struct sigaction結構體,這也是這個函數的難點所在,下面詳細說明:

struct 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);

};

這個結構體成員很多,又很多是回調函數的形式,令人望而生畏。但實際上,需要掌握的只有三個。

首先,sa_restorer和sa_sigaction這兩個成員一個已經被棄用了,另一個很少使用,所以我們暫且不管它們,重點掌握剩下的三個。

sa_handler:指定信號捕捉後的處理函數,即註冊回調函數。該成員也可以賦值為SIG_IGN,表示忽略該信號,也可註冊為SIG_DFL,表示執行信號的默認動作。

sa_mask:臨時阻塞信號集(或信號屏蔽字)先來看這樣一個情景:

某個信號已經註冊了回調函數,當內核傳遞這個信號過來時,會先經過一個阻塞信號集,先阻塞掉部分信號。再去執行對應的回調函數。如下圖示:

假如說,這個回調函數回調執行的時間比較長,比如2秒,在這2秒裡,又有其它的信號過來,那進程是暫停當前回調函數,去響應新的信號,還是不管新來的信號,先把當前回調函數處理完再說?

正確的做法是,在執行回調函數期間,使用sa_mask臨時的去替代進程的阻塞信號集,保證回調函數安心的執行完畢,再解除替代。注意:這個過程僅僅發生在回調函數執行期間,是臨時性的設置。

sa_flags:通常設置為0,表示使用默認屬性。

再來看另外一個場景:

比如進程對SIGQUIT註冊了回調函數,當回調函數在執行期間,又來了SIGQUIT函數,這時,進程是響應還是不響應該信號?這就是sa_flags的一個作用,當其設置為0時,表示使用默認屬性,也就是先不響應該信號,而是執行完回調函數再處理此信號。

另外,阻塞的常規信號不支持排隊,也就是說,執行回調函數期間,再來千百個同個信號時,系統只記錄一次。而後面的32個實時信號則支持排隊。

#include <stdio.h> #include <signal.h> #include <unistd.h> void func(int signal) { printf("SIGQUIT catched!\n"); sleep(2); //用來模擬回調函數執行很長時間 printf("func finished!\n");}int main(){ struct sigaction act; act.sa_handler = func; sigemptyset(&act.sa_mask); //先清空臨時阻塞信號集 sigaddset(&act.sa_mask, SIGINT); // 執行回調函數期間,屏蔽SIGINT act.sa_flags = 0; sigaction(SIGQUIT, &act, NULL); //註冊回調函數 while(1); return 0;}

> 2020 精選 阿里/騰訊等一線大廠 面試、簡歷、進階、電子書 「**良許Linux**」後臺回復「**資料**」免費獲取

#### 看完的都是真愛,點個讚再走唄?您的「三連」就是良許持續創作的最大動力!

1. 關注**原創**「**良許Linux**」,第一時間獲取最新Linux乾貨!

2. 後臺回復【資料】【面試】【簡歷】獲取精選一線大廠面試、自我提升、簡歷等資料。

3. 關注我的博客:[lxlinux.net](http://www.lxlinux.net)

相關焦點

  • Linux系統編程:信號捕捉
    信號的捕捉,說白了就是抓到一個信號後,執行我們指定的函數,或者執行我們指定的動作。下面詳細介紹兩個信號捕捉操作參數:signal和函數作用:註冊一個信號捕捉函數函數作用:與signal函數類似,用來註冊一個信號捕捉函數
  • Linux系統編程—信號集操作函數
    先來回顧一下未決信號集是怎麼回事。信號從產生到抵達目的地,叫作信號遞達。而信號從產生到遞達的中間狀態,叫作信號的未決狀態。系統提供的一個方法是,我們先創建一個跟阻塞信號集一樣的集合,再利用它去修改阻塞信號集。系統提供了一系列的信號集設定函數。
  • Linux系統編程-信號入門
    處理信號:Unix 系統提供了兩種方法來改變信號處置:signal() 和 sigaction()。signal()系統調用是設置信號處置的原始 API,所提供的接口比sigaction() 簡單。另一方面,sigaction() 提供了 signal() 所不具備的功能。
  • Linux系統編程—時序競態
    但由於系統資源競爭的原因,前後兩次執行的結果有可能得到不一樣的結果,這個現象就是時序競態。返回值:我們知道,信號的處理方式有三種:1. 默認動作;2. 忽略處理;3. 捕捉。進程收到一個信號後,會先處理響應信號,再喚醒pause函數。
  • Linux系統推薦學習的程式語言以及經驗
    First ;首先作為一個初學者,必須扎紮實實的掌握一門基礎的編程,計算機語言想通相似,想要學好編程,必須熟練地掌它握一門基礎計語言,這裡推薦學習C和C++;C++作為一門最難的語言,能掌握它,其他語言自然不在話下。
  • Linux系統編程—信號量
    於是,Linux系統提出了信號量的概念。這是一種相對比較折中的處理方式,它既能保證線程間同步,數據不混亂,又能提高線程的並發性。注意,這裡提到的信號量,與我們所學的信號沒有一點關係,就比如Java與JavaScript沒有任何關係一樣。
  • Linux下C編程基礎之:Linux下C語言編程概述
    儘管C語言不是專門針對UNIX作業系統或機器編寫的,但它與UNIX系統的關係十分緊密。由於它的硬體無關性和可移植性,使C語言逐漸成為世界上使用最廣泛的計算機語言。目前流行的C語言編譯系統都是以它為基礎的。C語言的成功並不是偶然的,它強大的功能和它的可移植性讓它能在各種硬體平臺上遊刃自如。總體而言,C語言有如下特點。(1)C語言是「中級語言」。它把高級語言的基本結構和語句與低級語言的實用性結合起來。C語言可以像彙編語言一樣對位、字節和地址進行操作,而這三者是計算機最基本的工作單元。
  • 盤點Linux作業系統下C語言編程注意事項
    編者按:  Linux作業系統下C語言編程注意事項,值得你一看。linux作業系統文章專題:linux作業系統詳解(linux不再難懂)  2、學會makefile文件的編寫規則,並結合使用工具aclocal、autoconf和automake生成makefile文件。  3、掌握gcc和gdb的基本用法。
  • Linux系統與Windows系統對比有哪些不同
    1、 編程篇 linux與windows對比 雖然五年已經過去了,但是系統編程的模式基本沒有什麼改變,由於GPL的存在linux在編程效率上比windows要高不少,這是因為GPL公開程序代碼,這樣可以減少重複開發,所以linux在編程模式上比windows要略微強點。
  • iOS基於unix,安卓基於linux,而國產系統基於linux就被吐槽?
    而國產系統這些年雖然在不斷的發展,但很明顯,一直處於邊緣地帶,沒有真正的走進普通消費者的電腦中。當然對於國產作業系統,也有人吐槽。說怎麼能稱之為國產作業系統呢,明明就是linux套了個馬甲而來,卻說是國產作業系統了。
  • 嵌入式Linux系統開發入門基礎
    2、Shell 編程基礎Shell簡介 認識後臺程序Bash編程熟悉Linux系統下的編輯環境 熟悉Linux下的各種Shell 熟練進行shell編程熟悉vi基本操作 熟悉Emacs的基本操作比較不同shell的區別 編寫一個測試伺服器是否連通的shell腳本程序 編寫一個查看進程是否存在的shell腳本程序 編寫一個帶有循環語句的shell腳本程序   3、Linux 下的 C 編程基礎linux C語言環境概述 Gcc使用方法 Gdb調試技術 Autoconf Automake Makefile 代碼優化 熟悉Linux系統下的開發環境 熟悉Gcc編譯器 熟悉Makefile
  • Linux驅動1-如何實現模塊化編程
    一、什麼是模塊化編程?上面這段代碼雖然很簡單,但是他包含了Linux內核模塊化編程需要的所有信息。 我們來一起總結一下Linux內核模塊化編程必備的步驟:第一步: 包含linux/init.h和inux/module.h這兩個頭文件;
  • linux系統股票交易軟體的製作
    linux我想大家並不陌生,我最近看論壇上好多人在修找基於linux系統的炒股軟體,基本上都是失望而歸,即使僥倖找到了,你看不懂原始碼,那麼也是很危險的一件事,誰知道代碼裡寫的是不是真的呢?,今天正好有時間,我們就來說一下在linux系統下的股票軟體的製作。
  • 明明是搭載linux系統的智慧型手機卻被摩託羅拉搞成功能機
    2003年摩託羅拉推出了世界首款採用了linux系統的手機A760。雖然摩託羅拉是Symbian系統的創始成員之一。進軍linux顯然有摩託羅拉更深層的考慮。第一,不想被諾基亞主導的Symbian控制,希望擁有自己可以控制的系統和生態。第二,當時的手機設計思想和現在不一樣,現在的手機是偏向娛樂化,日常化。
  • 明明是搭載linux系統的智慧型手機卻被摩託羅拉搞成功能機
    2003年摩託羅拉推出了世界首款採用了linux系統的手機A760。雖然摩託羅拉是Symbian系統的創始成員之一。進軍linux顯然有摩託羅拉更深層的考慮。第一,不想被諾基亞主導的Symbian控制,希望擁有自己可以控制的系統和生態。
  • AI 系統向自動化編碼邁進 | Linux 中國
    • 來源:linux.cn • 作者:Patrick Nelson • 譯者:geekpi •(本文字數:1496,閱讀時長大約:2 分鐘)最有趣的是,該系統有學習代碼的潛力,然後利用這種智能來改變軟體的編寫方式。最終,人們可以解釋希望程序做什麼,然後機器編程(MP)系統可以拿出一個已經編寫完的應用。
  • Linux系統入門命令學習經驗
    我大學的專業是電氣工程及其自動化,平時的課程也涉及不到linux,所以旁邊也沒有掌握linux的同學能夠一塊交流,通過自己這段時間的學習,我覺得有些學習總結可以簡單的介紹給大家,供大家在開始業餘學習linux的時候能夠作為一點參考。
  • 龍巖linux系統正版安裝定製_蘭吉德電子物美價廉
    龍巖linux系統正版安裝定製,蘭吉德電子物美價廉,公司與全球眾多頂級計算機軟硬體廠商建立多元化的合作關係,現已取得Microsoft、Oracle、Citrix、Anchiva、VMware、LANDesk、IBM、HP、Symantec、Adobe、Autodesk、Sybase、CA、TrendMicro、Cisco、H3C、EMC
  • 關於linux網絡編程的一些實用技巧和細節總結
    由於網絡編程涉及很多細節和技巧,一直想寫篇文章來總結下這方面的心得與經驗,希望對來者有一點幫助,那就善莫大焉了。需要注意的是:linux平臺上connect()暫時不能完成返回-1,錯誤碼可能是EINPROGRESS,也可能是由於被信號給中斷了,這個時候錯誤碼是:EINTR。
  • Linux信號量(3)-內核信號量
    我們有時候會等待電梯、洗手間,這種場景需要等待的時間並不是很多,如果我們還要找個地方睡一覺,然後等電梯到了或者洗手間可以用了再醒來,那很顯然這也沒有必要,我們只需要排好隊,刷一刷抖音就可以了,對比於電腦程式,比如驅動在進入中斷例程,在等待某個寄存器被置位,這種場景需要等待的時間往往很短暫,系統開銷甚至遠小於進入休眠的開銷,所以這種場景採用自旋鎖比較合適。