進程間通信(五)—信號

来源:http://www.cnblogs.com/lenomirei/archive/2016/07/09/5656449.html
-Advertisement-
Play Games

我會用幾篇博客總結一下在Linux中進程之間通信的幾種方法,我會把這個開頭的摘要部分在這個系列的每篇博客中都打出來 進程之間通信的方式 管道 消息隊列 信號 信號量 共用存儲區 套接字(socket) 進程間通信(三)—信號量傳送門:http://www.cnblogs.com/lenomirei/ ...


我會用幾篇博客總結一下在Linux中進程之間通信的幾種方法,我會把這個開頭的摘要部分在這個系列的每篇博客中都打出來

進程之間通信的方式

  • 管道
  • 消息隊列
  • 信號
  • 信號量
  • 共用存儲區
  • 套接字(socket)

進程間通信(四)—共用存儲區傳送門:http://www.cnblogs.com/lenomirei/p/5651995.html

進程間通信(三)—信號量傳送門:http://www.cnblogs.com/lenomirei/p/5649792.html

進程間通信(二)—消息隊列傳送門:http://www.cnblogs.com/lenomirei/p/5642575.html

進程間通信(一)—管道傳送門:http://www.cnblogs.com/lenomirei/p/5636339.html

我感覺這麼寫下去越來越不像進程間的通信了,更像是進程間的打招呼。。。信號就是這樣的,某某(這個某某有很多可能性)給進程一個信號,進程就會在適當的情況下處理這個信號這說明進程可能不會立即處理信號),什麼是適當的時候呢?比如說中斷返回的時候,或者內核態返回用戶態的時候(這個情況出現的比較多)等等(推薦本書《Linux內核設計與實現》,裡面講過)。。。這個也不是本篇的主題就不多述了。

首先來說信號是怎麼產生的

  • 由硬體產生,別入從鍵盤敲入組合鍵發送一個信號,常用的Ctrl+C就可以給前臺進程發送。
  • 由進程發送(或者說是由軟體產生),比如我們可以在shell進程下輸入kill命令給一個進程發送信號(命令:kill -信號標號 PID)
  • 異常,當異常的發生的時候肯定是會發送信號的

然後說信號的處理方式,誰來處理信號?肯定是操作系統來,難不成還是程式員麽。文章一開頭就說了,號不一定會被立即處理,操作系統不會為了處理一個信號而把當前正在運行的進程掛起(切換進程)或者殺掉(肯定不會殺掉啊,難道看見一個信號就殺害一個無辜群眾麽),掛起(進程切換)的話消耗太大了,如果不是緊急信號,可能是不會立即處理的。操作系統多選擇在內核態切換回用戶態的時候處理信號,這樣就利用兩者的切換來處理了(不用單獨進行進程切換以免浪費時間)。

總歸是不能避免的,因為很有可能在睡眠的進程就接收到信號,操作系統肯定不願意切換當前正在happy地跑著的進程,於是就得把信號儲存啊,因為是進程收到的信號,所以把信號儲存在進程唯一的PCB(就是task_struct)當中。struct sigpending pending;欄位就是存放信號的信號表,之後會解釋pending。

 信號的處理過程

所有的信號可以通過kill -l 命令查看

需要註意的幾點

  • 沒有0號信號
  • 沒有32,33號信號
  • 從31號信號分開,前面的是普通信號,後面的是實時信號,本篇介紹的是普通信號
  • 信號和前面的標號是一致的,可以使用標號,也可以使用巨集名稱

信號的處理方式有三種

  • 忽略(就是這麼6,你發啥我都不理你)
  • 預設處理方式,操作系統設定的預設處理方式,會終止一個進程,就是說接到信號就把這個進程幹掉了
  • 自定義處理方式,想乾什麼還是得我說了算,你需要一個signal函數
    • 函數原型:sighandler_t signal(int signum, sighandler_t handler);
    • 頭文件:#include <signal.h>
    • 參數解析:
      • 第一個是信號標號,給數字就可以啦
      • 關鍵是第二個參數這裡,sighandler_t是一個typedef來的,主要是為了可讀性,原型是void (*)(int)函數指針啦,int的參數會被設置成signum
      • 我有用到這個函數,可以在我的測試用例中看一下用法

 

  • 相關函數解析

這次就沒有創建函數什麼的了,主要是信號相關的一些操作函數,但是由於比較多和繁雜,不好每一個都寫測試用例看輸出結果,最後的測試程式只用了一部分函數,並沒有全部使用到

前面說了用kill命令可以給進程發信號,可是我想用C語言編寫程式發,別怕!你需要下麵的函數(raise函數只能給進程本身發信號

  • 函數原型:int raise(int signo);
  • 頭文件:#include <signal.h>
  • 參數解析:
    • 就一個參數就是信號了,可以用標號,也可以用巨集名

或者你說不想光給自己發信號,光自己是很沒意思,那麼看下麵這個函數

  • 函數原型:int kill(pid_t pid, int signo);
  • 頭文件:#include <signal.h>
  • 參數解析:
    • 第一個參數是pid進程號,你得讓操作系統知道你要給哪個進程發信號,給自己發也是可以的哦
    • 第二個參數是信號。。。呃,準確的說是哪個信號,可以用標號,也可以用巨集名

看這個信號(6) SIGABRT,這個信號可以讓進程異常終止,他有一個對應的函數

  • 函數原型:void abort(void);
  • 頭文件:#include <stdlib.h>
  • 參數解析:
    • 這根本就沒有參數嘛!那就寫點其他的。
    • 該函數沒有返回值,因為該函數執行絕對不會失敗(為什麼?殺個進程而已,談什麼失敗(一刀不行就兩刀!!(玩笑))),和exit函數一樣絕對不會失敗(重要!說兩遍!)和exit函數不同的地方是,exit會設置退出碼。

看這個信號(14) SIGALRM,這個信號是鬧鐘信號,它可以由這個函數發送

  • 函數原型:unsigned int alarm(unsigned int seconds);
  • 頭文件:#include <unistd.h>
  • 參數解析:
    • 參數都寫的這麼清楚了!等待多少秒之後就會發送SIGALRM信號給當前進程。

接下來說明一下阻塞信號,就是(pending)了

  • 阻塞信號(pending signal)

之前提到過,可以忽略一個信號,那麼我說,阻塞和忽略是不一樣的阻塞是進程收不到該信號,忽略是進收到該信號,卻不做出任何反應

實際執行信號的處理動作稱為信號遞達(Delivery),信號從產生到遞達之間的狀態,稱為信號未決(Pending)。進程可以選擇阻塞(Block )某個信號。被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。

task_struct中有類似欄位,之前說的信號可能不會立即被執行就會存儲在pending表裡面

其中一旦信號被block,當有信號產生的時候會一直pending,因為未決就是未處理的意思,block到不了就處理不了,pending會一直有該位

以為PCB中使用32位來表示上圖中的block和pending表,所以非實時信號就算發送多個,也只顯示一個。實時信號會排隊,有幾個來就有幾個排隊

block表:某位為0表示該位對應標號的信號未被阻塞,為1表示阻塞

pending表:某位為0表示信號還未產生或者已經被處理

上圖中2號信號兩個表同時為1表示產生了2號信號,但因為2號信號被阻塞所以一直未決。

介紹幾個操作這兩張表的函數

  • 函數原型:

    int sigemptyset(sigset_t *set);用於初始化一個信號集(新創建出來的sigset_t對象都要先執行這個函數再去操作)
    int sigfillset(sigset_t *set);初始化信號集,所有位置位1,表示支持所有信號(就好像添加了所有的信號)
    int sigaddset(sigset_t *set, int signo);把感興趣的(想要操作)信號添加到信號集

    int sigdelset(sigset_t *set, int signo);把感興趣的(想要操作)信號從信號集踢出去
    int sigismember(const sigset_t *set, int signo);判斷你傳入的signo是否是set集合中的一員

  • 頭文件:#include <signal.h>
  • 參數解析:
    • sigset_t結構體的參數表示信號集信號操作的時候都是以信號集合的方式進行操作,需要事先創建一個該結構體的對象,然後把想要操作的信號添加到信號集合對象當中去
    • signo就是信號的標號了

如何阻塞一個信號?用下麵的函數

  • 函數原型:int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
  • 頭文件:#include <signal.h>
  • 參數解析:
    • 先說how,有三個巨集
      • SIG_BLOCK添加到block表當中去
      • SIG_UNBLOCK從block表中刪除
      • SIG_SETMASK設置block表(跟第一個SIG_BLOCK不同,這個是直接讓當前進程和set完全相等,不是把set的添加到當前block表中去了)  
    • set表示要設置的集合,比如你集合裡面有1234,就這些,那麼這個函數就把這幾個根據第一個參數how進行設置
    • oset表示old set就是設置之前保存一下之前的block表信息,可以給NULL

如何獲取當前pending表中的信息?你需要它~

  • 函數原型:int sigpending(sigset_t *set);
  • 頭文件:#include <signal.h>
  • 參數解析
    • 這是一個輸出型參數,會把當前進程的pending表列印到傳入的set集中

 事已至此,基本操作就說完了,廢話少說,show me the code

功能看結果圖:先貼結果圖,一開始沒有任何信號,所以pending表中全是0,我通過Ctrl+C傳入2號信號,看到pending表中有2號被置位了,經過10秒取消阻塞,2號信號被處理(經過我自定義的函數)

我的程式只有一個文件server.c

 1 #include <stdio.h>
 2 #include <sys/signal.h>
 3 #include <sys/types.h>
 4 #include <signal.h>
 5 
 6 
 7 
 8 void func(int num)
 9 {
10   printf("catch signal number is %d",num);
11 
12 }
13 
14 
15 void printfpendingsignal(sigset_t *set)
16 {
17   int i;
18   for(i=1;i<32;++i)
19   {
20     if(sigismember(set,i))
21     {
22       printf("1");
23 
24     }
25     else
26     {
27       printf("0");
28     }
29   }
30   printf("\n");
31 }
32 
33 
34 int main()
35 { 
36   sigset_t s,p,o;
37   signal(SIGINT,func);
38   sigemptyset(&s);
39   sigemptyset(&p);
40   sigemptyset(&o);
41   sigaddset(&s,SIGINT);
42   sigprocmask(SIG_SETMASK,&s,&o);
43   int count=0;
44   while(1)
45   {
46     sigpending(&p);
47     printfpendingsignal(&p);
48     sleep(1);
49     if(count++==10)
50     {
51       printf("recover!\n");
52       sigprocmask(SIG_SETMASK,&o,NULL);
53     }
54   }
55   return 0;
56 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說明 寫這個目錄是為了方便閱讀。也是為了記錄統一的問題。 這個系列,並不一定是全的,也不一定是對的,所以請大家多做過濾。 這裡面場景比較多的是本人在實踐中遇到的問題,然後自己思考抽象的。 目錄 1. "web安全——簡介" 2. "web安全——防火牆" 3. "web安全——系統(Linux)" ...
  • 簡介 數據安全是現在互聯網安全非常重要一個環節。而且一旦數據出現問題是不可逆的,甚至是災難性的。 有一些防護措施應該在前面幾個博文說過了,就不再贅述。比如通過防火牆控制,通過系統的用戶控制,通過web應用的控制等。 想說的是,任何一個節點都不是單獨存在的。 場景 1. 確保應用本身安全。 2. 控制 ...
  • 簡介 由於網路技術日趨成熟,黑客們也將註意力從以往對網路伺服器的攻擊逐步轉移到了對web應用的攻擊。據最新調查,信息安全有75%都發生在web應用而非網路層面。 場景 1. 控制訪問的許可權。只讓可以訪問的訪問到最小的資源和許可權。 2. 控制輸入內容。所有輸入都可能是不安全的,所以要過濾。 3. 保證 ...
  • 什麼是MVP?在“MVP初探”里就有講過了,就是一種UI的架構模式。 什麼是Unity、PIAB、Exception Handling?可以去Bing一下。 為使M/V/P之間更好的解耦,我們通過引入Enterprise Library的Exception Handling Application ...
  • 簡介 最小(少)原則,是安全的重要原則。最小的許可權,最小的用戶,最少的服務,最少的進程,是最安全的。 系統安全包括:文件系統保護、用戶管理安全、進程的保護以及日誌的管理。 場景 1. 確保服務最少,每個都是有用,而且許可權最小化。 2. 確保用戶最少,每個都是有用,而且許可權最小化。 3. 確保文件許可權 ...
  • Ubuntu 固定IP 1. 更改/etc/network/interfaces的內容 1.1 註釋掉原來的內容 1.2 添加以下內容 auto eth0 iface eth0 inet static address 192.168.1.119 netmask 255.255.255.0 getew ...
  • 在RHEL5.x版本下麵,在添加磁碟分區等操作後,一直使用partproble命令使內核重新讀取分區表信息,從而不用重新啟動。但是最近在RHEL 6(Red Hat Enterprise Linux Server release 6.6 (Santiago))下,使用partprobe出現錯誤。 [... ...
  • Kubernetes為Google開源的容器管理框架,提供了 Docker容器的誇主機、集群管理、容器部署、高可用、彈性伸縮 等一系列功能;Kubernetes的設計目標包括使容器集群任意時刻都處於用戶期望的狀態,因而建立了一整套集群管理機制:容器自動重啟、自動備份、容器自動伸縮等;Kubernet ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...