最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux進(jìn)程信號(hào)的用法及說(shuō)明

 更新時(shí)間:2025年07月28日 16:54:16   作者:QQ_437664314  
Linux信號(hào)是進(jìn)程間異步通知機(jī)制,分傳統(tǒng)(1-31)與實(shí)時(shí)(34-64)信號(hào),處理方式包括默認(rèn)、忽略和自定義,通過(guò)阻塞信號(hào)可控制其遞達(dá),系統(tǒng)調(diào)用如sigprocmask和sigpending用于管理信號(hào)狀態(tài)與處理

信號(hào)產(chǎn)生

生活中的信號(hào)類(lèi)比(交通信號(hào)燈、警報(bào)),當(dāng)產(chǎn)生這些信號(hào)時(shí),我們會(huì)立馬想到對(duì)應(yīng)的動(dòng)作。

在Linux中,信號(hào)是事件發(fā)生對(duì)進(jìn)程的通知機(jī)制亦稱(chēng)軟件中斷,由操作系統(tǒng)內(nèi)核、進(jìn)程本身或者其他進(jìn)程向目標(biāo)進(jìn)程異步事件發(fā)送機(jī)制(即收到某種信號(hào),并不會(huì)立馬去執(zhí)行)。通知進(jìn)程發(fā)生某種預(yù)定義的時(shí)間,要求進(jìn)程作出相應(yīng)響應(yīng)。

信號(hào)與硬件中斷相似之處在于會(huì)打斷程序執(zhí)行流程。

常見(jiàn)信號(hào)

硬件異常

  • 如內(nèi)存越界(SIGSEGV
  • 除零錯(cuò)誤(SIGFPE
  • 由內(nèi)核自動(dòng)生成

系統(tǒng)調(diào)用:

  • kill():向指定進(jìn)程發(fā)送信號(hào)
  • raise():進(jìn)程向自身發(fā)送信號(hào)
  • alarm():設(shè)置定時(shí)器,超時(shí)后發(fā)送 SIGALRM

終端輸入:

  • Ctrl+C:SIGINT(終止進(jìn)程)
  • Ctrl+Z:SIGTSTP(暫停進(jìn)程)
  • Ctrl+\:

軟件條件:

  • 子進(jìn)程退出時(shí),父進(jìn)程收到 SIGCHLD
  • 定時(shí)器到期(如 alarm())觸發(fā)信號(hào)

核心轉(zhuǎn)儲(chǔ) :

信號(hào)的分類(lèi)

信號(hào)分為兩大類(lèi)。

(編號(hào)1-31)為傳統(tǒng)信號(hào)信號(hào),內(nèi)核向進(jìn)程通知且遞送一次,(編號(hào)34-64)為實(shí)時(shí)信號(hào)使信號(hào)按序遞送。

信號(hào)處理方式

  • 默認(rèn)動(dòng)作: 部分是終止自己,暫停等
  • 忽略動(dòng)作: 是一種信號(hào)處理的方式,只不過(guò)動(dòng)作就是什么都不干
  • 自定義動(dòng)作: 使用signal方法修改信號(hào)的處理動(dòng)作。(即用戶程序員編寫(xiě)的函數(shù):將默認(rèn)動(dòng)作轉(zhuǎn)化為自定義動(dòng)作)

改變信號(hào)處理方式

signal,sigaction

信號(hào)阻塞

概念悉知

  • 實(shí)際執(zhí)行信號(hào)的處理動(dòng)作稱(chēng)為信號(hào)遞達(dá)(Delivery)
  • 信號(hào)從產(chǎn)生到遞達(dá)之間的狀態(tài),稱(chēng)為信號(hào)未決(Pending)。
  • 進(jìn)程可以選擇阻塞 (Block )某個(gè)信號(hào)。
  • 被阻塞的信號(hào)產(chǎn)生時(shí)將保持在未決狀態(tài),直到進(jìn)程解除對(duì)此信號(hào)的阻塞,才執(zhí)行遞達(dá)的動(dòng)作.
  • 阻塞和忽略是不同的,只要信號(hào)被阻塞就不會(huì)遞達(dá),而忽略是在遞達(dá)之后可選的一種處理動(dòng)作。

信號(hào)產(chǎn)生后會(huì)稍后遞達(dá)給某進(jìn)程,信號(hào)在產(chǎn)生和到達(dá)期間會(huì)一直處于pending等待狀態(tài)。

信號(hào)在內(nèi)核中的表示

每個(gè)進(jìn)程都有一個(gè)信號(hào)屏蔽字亦稱(chēng)阻塞信號(hào)集,一個(gè) sigset_t 類(lèi)型的位圖,每一位對(duì)應(yīng)一個(gè)信號(hào)(如 SIGINT、SIGQUIT 等)。用來(lái)標(biāo)記哪些信號(hào)當(dāng)前被阻塞。被阻塞的信號(hào)若已產(chǎn)生,會(huì)進(jìn)入未決狀態(tài),直到阻塞被解除才會(huì)觸發(fā)處理。位為1生效,0不生效。

block與pending之間聯(lián)系

pending集是信號(hào)產(chǎn)生后的暫存區(qū),block是控制信號(hào)是否能從pending暫存區(qū)遞交給進(jìn)程的開(kāi)關(guān)

  • block:決定哪些信號(hào)會(huì)被阻塞,近而將其放入未決信號(hào)集
  • pending:記錄已產(chǎn)生但未被處理的信號(hào)(因被阻塞或正在處理其他信號(hào))
  • 通過(guò)sigpending()査詢(xún)掛起的信號(hào)集,通過(guò)sigprocmask()控制阻塞狀態(tài)。

其中block位圖用于表示進(jìn)程是否阻塞。

  • pending位圖用于是否有信號(hào)寫(xiě)入(信號(hào)是否產(chǎn)生,信號(hào)產(chǎn)生時(shí),內(nèi)核在進(jìn)程控制塊中設(shè)置該信號(hào)的pending位圖,直到信號(hào)抵達(dá)才消失)。
  • handler函數(shù)指針數(shù)組用于進(jìn)程執(zhí)行何種動(dòng)作(其中存放的是動(dòng)作函數(shù)指針,每個(gè)信號(hào)的編號(hào)就是其數(shù)組下標(biāo))。

關(guān)鍵系統(tǒng)調(diào)用

信號(hào)集操作函數(shù)

sigset_t 本質(zhì)上是一個(gè)位圖,每一位代表一個(gè)信號(hào)。當(dāng)某一位被設(shè)置為 1 時(shí),表示對(duì)應(yīng)的信號(hào)被包含在信號(hào)集中;為 0 則表示不包含。使用者只能調(diào)用以下函數(shù)來(lái)操作sigset_t變量,不用關(guān)注內(nèi)部數(shù)據(jù)。

在使用sigset_t類(lèi)型的變量之前,一定要調(diào)用sigemptyset()函數(shù)初始化一個(gè)未包含任何成員的信號(hào)集或者sigfillset()函數(shù)則初始化一個(gè)信號(hào)集,使其包含所有信號(hào)(包括所有實(shí)時(shí)信號(hào))。

#include <signal.h>
// 清空信號(hào)集,置0
int sigemptyset(sigset_t *set);  
// 填充所有信號(hào), 置有效狀態(tài)1?  
int sigfillset(sigset_t *set);     

信號(hào)集初始化后,可以分別使用 sigaddset()sigdelset()函數(shù)向一個(gè)集合中添加或者移除單個(gè)信號(hào)。使用sigismember()測(cè)試信號(hào)是否是信號(hào)集set的成員。

#include <signal.h>
// 添加單個(gè)信號(hào)
int sigaddset(sigset_t *set, int signo); 
 // 刪除單個(gè)信號(hào)
int sigdelset(sigset_t *set, int signo);
// 判斷信號(hào)是否存在
int sigismember(const sigset_t *set, int signo); 

信號(hào)掩碼(阻塞信號(hào)傳遞)

內(nèi)核會(huì)為每個(gè)進(jìn)程維護(hù)一個(gè)信號(hào)掩碼(一組信號(hào)),阻塞其針對(duì)該進(jìn)程的傳遞。如果將被阻塞的信號(hào)發(fā)送給某進(jìn)程,那么對(duì)該信號(hào)的傳遞將延后,直至從進(jìn)程信號(hào)掩碼中移除該信號(hào),從而解除阻塞為止。阻塞信號(hào)集內(nèi)01只能由其觸發(fā)。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

參數(shù) :

how:指定了sigprocmask()函數(shù)想給信號(hào)掩碼帶來(lái)的變化。

  • SIG_BLOCK:set包含了我們希望添加到當(dāng)前信號(hào)屏蔽字的信號(hào)(邏輯或)
  • SIG_UNBLOCK:set包含了我們希望從當(dāng)前信號(hào)屏蔽字中解除阻塞的信號(hào)(與非)
  • SIG_SETMASK:設(shè)置當(dāng)前信號(hào)屏蔽字為set所指向的值(直接賦值)

set

  • 要操作的信號(hào)集,(為NULL則忽略)

oldset

  • 保存舊的信號(hào)掩碼(可為NULL)

返回值:成功返回 0,失敗返回 -1(設(shè)置 errno

  • 阻塞:信號(hào)暫存到未決信號(hào)集直到解除阻塞
  • 忽略:直接丟棄

操作示例:

void handler(int no){
    cout << "execcute user-defined actions" << " ";
}

int main(){

    //更改2號(hào)信號(hào)執(zhí)行動(dòng)作
    signal(2, handler);

    //創(chuàng)建兩個(gè)信號(hào)集
    sigset_t set, old_set; 

    //清空信號(hào)集
    sigemptyset(&set);
    sigaddset(&set, SIGINT);//將2號(hào)信號(hào)添加進(jìn)set集01000...000
    
    //將set信號(hào)集中指定信號(hào)添加到當(dāng)前阻塞信號(hào)集中,同時(shí)將原來(lái)的信號(hào)集保存到old_set中
    sigprocmask(SIG_BLOCK, &set, &old_set);//阻塞set中包含的信號(hào)集

    cout << "SIG_INT is blocked, ctrl+c has failed" << endl;
    sleep(5);//5秒內(nèi)ctrl+c不會(huì)有反應(yīng)

    //使用old_set替換當(dāng)前所有阻塞信號(hào)集
    sigprocmask(SIG_SETMASK, &old_set, NULL);//恢復(fù)之前阻塞信號(hào)集
    cout << "SIG_INT has been resloved" << endl;
    sleep(5);
    return 0;
}

阻塞期間發(fā)送2號(hào)信號(hào)?

信號(hào)不會(huì)立馬處理,而是將該信號(hào)加入pending信號(hào)集(即pending位圖SIG_INT位從0-->1)

信號(hào)阻塞接觸后?

pending信號(hào)集內(nèi)該信號(hào)立即處理(處理方式鑒于默認(rèn)動(dòng)作忽略(丟棄)自定義動(dòng)作),該位由1-->0

sigpending獲取未決信號(hào)集

如果某進(jìn)程接受了一個(gè)該進(jìn)程正在阻塞的信號(hào),那么會(huì)將該信號(hào)填加到進(jìn)程的等待信號(hào)集中。當(dāng)之后解除了對(duì)該信號(hào)的鎖定時(shí),會(huì)隨之將信號(hào)傳遞給此進(jìn)程。

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

系統(tǒng)調(diào)用返回后,用戶空間的set變量包含了當(dāng)前的未決信號(hào)集,可以使用sigismember()檢查特定信號(hào)是否在未決信號(hào)集中。 

作用: 返回處于等待狀態(tài)的信號(hào)集,并將其置于 set指向的sigset_t 結(jié)構(gòu)中。

操作是否進(jìn)入未決?后續(xù)動(dòng)作
信號(hào)被阻塞,且期間被發(fā)送該信號(hào)記錄在未決信號(hào)集中,直到阻塞解除后被處理
信號(hào)被阻塞,期間未被發(fā)送不記錄該信號(hào),解除阻塞后若收到信號(hào)則直接處理
信號(hào)未被阻塞,但被發(fā)送信號(hào)直接調(diào)用對(duì)應(yīng)函數(shù)即可

signal() - 設(shè)置信號(hào)處理

#include <signal.h>

void (*signal(int sig, void (*func)(int)))(int);

返回函數(shù)指針的函數(shù):

代碼示例:

void handler(int signo){
    cout << "execcute user-defined actions" << " ";
}
...
    //更改2號(hào)信號(hào)執(zhí)行動(dòng)作
    signal(2, handler);

聲明該函數(shù)類(lèi)型是一個(gè)函數(shù)指針類(lèi)型,signal是函數(shù)名(如:int (*p)(int,int),p是函數(shù)名,有兩個(gè)int類(lèi)型參數(shù),返回值是一個(gè)int類(lèi)型)。signal返回的是一個(gè)函數(shù)指針,該函數(shù)指向的函數(shù)參數(shù)是一個(gè)int類(lèi)型,返回值是void。所以外層是指明這是一個(gè)函數(shù)指針類(lèi)型。里面才是使用的函數(shù)本體。

  • signal 是一個(gè)函數(shù)
  • 它接受一個(gè)整數(shù)和一個(gè)函數(shù)指針作為參數(shù)
  • 它返回一個(gè)與第二個(gè)參數(shù)類(lèi)型相同的函數(shù)指針

返回函數(shù)指針的數(shù)組: 對(duì)?

sigaction() - 設(shè)置信號(hào)處理

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

signum : 目標(biāo)信號(hào)

act 新的信號(hào)處理方式

  • sa_handler:信號(hào)處理函數(shù)指針(或 SIG_IGN、SIG_DFL)。
  • sa_mask:處理該信號(hào)時(shí)額外阻塞的信號(hào)集。
  • sa_flags:控制選項(xiàng)(如 SA_RESTARTSA_NODEFER
  • NULL

oldact

  • 保存舊的處理配置(可為NULL)

返回值:成功返回 0,失敗返回 -1(設(shè)置 errno

struct sigaction {
    void     (*sa_handler)(int);          // 簡(jiǎn)單處理函數(shù)
    void     (*sa_sigaction)(int, siginfo_t *, void *); // 高級(jí)處理函數(shù)
    sigset_t sa_mask;                     // 處理期間屏蔽的信號(hào)集
    int      sa_flags;                    // 控制標(biāo)志
    void     (*sa_restorer)(void);        // 內(nèi)部使用(已廢棄)
};

現(xiàn)在我們使用sigprocmask函數(shù)和sigpending函數(shù)完成一個(gè)函數(shù)。思路是

  1. 對(duì)2號(hào)信號(hào)寫(xiě)入信號(hào)集
  2. 將該信號(hào)集使用sigprocmask函數(shù)將2號(hào)信號(hào)block住
  3. 我們鍵盤(pán)輸入ctrl+c,產(chǎn)生2號(hào)信號(hào),發(fā)送至該進(jìn)程。
  4. 使用sigpending函數(shù)輸出pending位圖,因?yàn)槲覀儗?code>2號(hào)進(jìn)程block住了,該信號(hào)并不能抵達(dá)。我們?cè)傧蚱浒l(fā)送2號(hào)信號(hào),信號(hào)被block住了并不會(huì)影響信號(hào)的寫(xiě)入。因此我們?cè)侔l(fā)送2號(hào)進(jìn)程之前pending位圖應(yīng)該全為0,發(fā)送2號(hào)進(jìn)程之后會(huì)看見(jiàn)pending位圖發(fā)送由01的變化。

執(zhí)行流程:

  1. 前 5 秒內(nèi),SIGINT(Ctrl+C)被阻塞,信號(hào)進(jìn)入未決狀態(tài)但不觸發(fā)處理。
  2. 5 秒后解除阻塞,若之前有未決的 SIGINT,會(huì)立即觸發(fā) handle 函數(shù)。
#include <iostream>
#include <cassert>
#include <unistd.h>
#include <signal.h>
using namespace std;
static void handler(int signo){
    cout << signo << " 號(hào)信號(hào)確實(shí)遞達(dá)了" << endl;
    //最終不退出進(jìn)程
}
 void DisplayPending(const sigset_t pending){
    // 打印 pending 表
    int i = 1;
    while (i < 32)
    {
        if (sigismember(&pending, i))  cout << "1";
        else cout << "0";
        i++;
    } cout << endl;
}
int main(){
    // 更改 2 號(hào)信號(hào)的執(zhí)行動(dòng)作
    signal(2, handler);
    // 創(chuàng)建信號(hào)集
    sigset_t set, oset;
    // 信號(hào)集清空  0
    sigemptyset(&set);
    sigemptyset(&oset);
    
    sigaddset(&set, 2);	//將2號(hào)信號(hào)寫(xiě)入set
    // 設(shè)置當(dāng)前進(jìn)程的屏蔽信號(hào)集
    sigprocmask(SIG_BLOCK, &set, &oset);//0給進(jìn)程
    // 死循環(huán)
    int n = 0;
    while (true){
        if (n == 5){
            // 采用 SIG_SETMASK 的方式,覆蓋進(jìn)程的 block 表
            sigprocmask(SIG_SETMASK, &oset, NULL); // 不接收進(jìn)程的 block 表
        }
        // 獲取進(jìn)程的 未決信號(hào)集
        sigset_t pending;
        sigemptyset(&pending);
        int ret = sigpending(&pending);
        assert(ret == 0);
        (void)ret; // 避免 release 模式中出錯(cuò)
        DisplayPending(pending);
        n++;
        sleep(1);
    }
    return 0;
}

信號(hào)處理

進(jìn)程地址空間

為了進(jìn)程可以通過(guò)訪問(wèn)虛擬地址來(lái)間接訪問(wèn)物理資源,我們需要建立虛擬地址空間與物理內(nèi)存的映射關(guān)系。用戶區(qū)和內(nèi)核區(qū)都需要通過(guò)內(nèi)核級(jí)頁(yè)表或者用戶級(jí)頁(yè)表進(jìn)行映射使用。

系統(tǒng)調(diào)用:

系統(tǒng)調(diào)用是受控的內(nèi)核入口,借助于這一機(jī)制,進(jìn)程可以請(qǐng)求內(nèi)核以自己的名義去執(zhí)行某些動(dòng)作。以應(yīng)用程序編程接口(API)的形式,內(nèi)核提供有一系列服務(wù)供程序訪問(wèn)。

信號(hào)處理過(guò)程

用戶態(tài)的時(shí)候執(zhí)行用戶代碼,在中斷/異常/系統(tǒng)調(diào)用的時(shí)候切換到內(nèi)核態(tài),査看進(jìn)程的三張表。(信號(hào)捕捉過(guò)程)當(dāng)需要執(zhí)行自定義動(dòng)作的時(shí)候,切回用戶態(tài)執(zhí)行自定義動(dòng)作,自定動(dòng)作完成之后,再切到內(nèi)核態(tài)執(zhí)行sys_sigretur()函數(shù),最后再切回用戶態(tài)中用戶代碼的下一行繼續(xù)執(zhí)行。

當(dāng)執(zhí)行默認(rèn)動(dòng)作或者忽略動(dòng)作的時(shí)候,直接可以在內(nèi)核中完成,完成之后切回用戶態(tài)中的用戶代碼的下一行,繼續(xù)執(zhí)行。

  • sigaction()
  • volatile關(guān)鍵字
  • SIGCHLD

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 關(guān)于linux分區(qū),文件系統(tǒng),目錄結(jié)構(gòu)的概述

    關(guān)于linux分區(qū),文件系統(tǒng),目錄結(jié)構(gòu)的概述

    下面小編就為大家?guī)?lái)一篇關(guān)于linux分區(qū),文件系統(tǒng),目錄結(jié)構(gòu)的概述。小編覺(jué)得挺不錯(cuò)的?,F(xiàn)在就分享給大家。也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12
  • 在后臺(tái)運(yùn)行Linux命令的方法

    在后臺(tái)運(yùn)行Linux命令的方法

    這篇文章主要介紹了在后臺(tái)運(yùn)行Linux命令的方法,幫助大家更好的理解和學(xué)習(xí)Linux,感興趣的朋友可以了解下
    2020-08-08
  • Linux之信號(hào)的保存方式

    Linux之信號(hào)的保存方式

    這篇文章主要介紹了Linux之信號(hào)的保存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Ubuntu 20.04缺少libssl.so.1.0.0錯(cuò)誤的解決方案

    Ubuntu 20.04缺少libssl.so.1.0.0錯(cuò)誤的解決方案

    在使用Ubuntu 20.04時(shí),你可能會(huì)遇到一些較老的應(yīng)用程序因缺少libssl.so.1.0.0庫(kù)而無(wú)法運(yùn)行的問(wèn)題,這是因?yàn)閁buntu 20.04默認(rèn)使用的是更新版本的OpenSSL庫(kù),本文將介紹如何快速解決這個(gè)問(wèn)題,需要的朋友可以參考下
    2025-11-11
  • Linux?SNMP團(tuán)體號(hào)配置指定IP地址訪問(wèn)的方法

    Linux?SNMP團(tuán)體號(hào)配置指定IP地址訪問(wèn)的方法

    這篇文章主要介紹了如何配置SNMP服務(wù)以限制對(duì)服務(wù)器的訪問(wèn),包括使用snmpd.conf文件和iptables防火墻,建議使用復(fù)雜的團(tuán)體號(hào),實(shí)施最小權(quán)限原則,并限制IP地址,通過(guò)這些方法,可以顯著提高SNMP服務(wù)的安全性,需要的朋友可以參考下
    2025-11-11
  • Linux中一種友好的find替代工具(fd命令)

    Linux中一種友好的find替代工具(fd命令)

    這篇文章主要介紹了Linux中一種友好的find替代工具(fd命令),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • shell腳本設(shè)置防止暴力破解ssh

    shell腳本設(shè)置防止暴力破解ssh

    大家好,本篇文章主要講的是shell腳本設(shè)置防止暴力破解ssh,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • linux下如何進(jìn)制的相互轉(zhuǎn)換

    linux下如何進(jìn)制的相互轉(zhuǎn)換

    文章介紹了Linux Shell和Python中不同進(jìn)制(二進(jìn)制、八進(jìn)制、十進(jìn)制、十六進(jìn)制)的轉(zhuǎn)換方法,包括前綴和轉(zhuǎn)換工具的使用
    2024-11-11
  • 如何解決Kali?Linux?APT更新中的GPG簽名錯(cuò)誤問(wèn)題

    如何解決Kali?Linux?APT更新中的GPG簽名錯(cuò)誤問(wèn)題

    這篇文章主要介紹了如何解決Kali?Linux?APT更新中的GPG簽名錯(cuò)誤問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • 用DNSPod和Squid打造自己的CDN (六) 編譯并安裝Squid

    用DNSPod和Squid打造自己的CDN (六) 編譯并安裝Squid

    這篇文章主要介紹centos下編譯并安裝Squid的方法,需要的朋友可以參考下
    2013-04-04

最新評(píng)論

思南县| 拉萨市| 高密市| 栾城县| 水城县| 西华县| 左贡县| 罗城| 印江| 阳山县| 金堂县| 屯昌县| 桂林市| 定襄县| 永川市| 定安县| 正安县| 吉隆县| 青州市| 新丰县| 鄂托克前旗| 衡阳县| 达拉特旗| 合阳县| 龙川县| 陆良县| 遵化市| 镇沅| 南雄市| 太仓市| 灯塔市| 金沙县| 汶上县| 和田县| 卫辉市| 靖安县| 平昌县| 那曲县| 鹤岗市| 固始县| 永福县|