Linux系統程式設計 訊號

2021-10-25 04:37:58 字數 4568 閱讀 3831

訊號處理雖然初學者用的不會很多,而且現有太多對訊號的替代品。但作為乙個打算專精發展的coder來說,還是必須學習和掌握的。

linux下,乙個程序給其他程序傳送訊號的api是kill函式

#include

#include

intkill

(pid_t pid,

int sig)

;

sig 引數決定了要傳送的訊號,pid決定要傳送的程序物件。

pid引數

含義pid > 0

訊號傳送給pid為pid的程序

pid = 0

訊號發給本程序組內的其他程序

pid = -1

訊號傳送給除init程序外的所有程序

pid < -1

訊號傳送給組id為-pid的程序組中的成員

linux定義的訊號值都大於0,sig取值為0,則kill函式不會傳送任何訊號。

該函式成功返回0,失敗則返回-1,並設定errno

errno

含義einval

無效的訊號

eperm

該程序沒有許可權傳送訊號給任何乙個目標程序

esrch

目標程序或程序組不存在

目標收到訊號時,需要乙個接收函式來進行處理

#include

typedef

void

(*__sighandler_t)

(int

);

訊號處理函式只帶有乙個整形引數,該引數用來指示訊號型別。 訊號處理函式應該是可重入的的,防止引發一些競態條件。

除了使用者自定義的,還有系統自帶的兩個訊號處理方式——sig_ign和sig_del

#include

#define std_dfl((__sighandler_t) 0)

#define std_ign((__sighandler_t) 1)

sig_ign 表示忽略目標訊號,sig_del表示使用訊號的預設處理方式。訊號預設的處理方式有:結束程序(term)、忽略訊號(ign)、結束程序並生成核心轉儲檔案(core)、暫停程序(stop)、以及繼續程序(cont)。

linux的可用喜好都定義在bits/signum.h標頭檔案中,其中包括標準訊號和posix實時訊號。

其中和網路程式設計比較密切的訊號有: sighub、sigpipe、sigurg。

如果程式在執行處於阻塞狀態的系統呼叫時接收到訊號,並且我們為給訊號設定了訊號處理函式,則預設情況下系統呼叫將被中斷,並且error被設定為eintr。我們可以使用sigaction函式為訊號設定sa_restart標誌以自動重啟該訊號終端的系統呼叫。

要為乙個訊號設定處理函式,可以使用signal系統呼叫

#include

_sighandler_t signal

(int sig, _sighandler_t _handler)

sig 引數指出要捕獲的訊號型別。_handler引數職責是_sighandler_t型別的函式指標,用於指定訊號sig的處理函式。

signal成功後,返回乙個函式指標,改函式指標的型別也是_sighandler_t。這個返回值是上次使用signal函式傳入的函式指標,或者是訊號sig對應的預設處理函式指標sig_def(如果是第一次呼叫signal的話)。

signal系統呼叫出錯時返回sig_err,並設定errno。

相比於signal函式,有更健壯的系統呼叫

#include

intsigaction

(int sig,

const

struct sigaction* act,

struct sigaction* oact)

;

sig引數指出要捕獲的訊號型別,act引數指定新的訊號處理方式,oact引數則輸出訊號先前的處理方式(如果不為null的話)。

其定義如下(博文最下方有完整的定義):

struct sigaction

__sigaction_handler;

// 此引數和signal()的引數handler相同,代表新的訊號處理函式

__sigset_t sa_mask;

//用來設定在處理該訊號時暫時將sa_mask 指定的訊號集擱置

int sa_flags;

// 用來設定訊號處理的其他相關操作

void

(*sa_restorer)

(void);

//已過時,最好不要使用

};

sigaction成功時返回0,失敗則返回-1並設定errno。

ps:init程序

它是核心啟動的第乙個使用者級程序。init有許多很重要的任務,比如像啟動getty(用於使用者登入)、實現執行級別、以及處理孤立程序。

linux使用資料結構sigset_t來表示一組訊號。

#include

#define _sigset_nwords (1024 / (8 * sizeof (unsigned long int)))

typedef

struct

__sigset_t;

由定義可見,sigset_t實際上是乙個長整型陣列,陣列的每個元素的每個位表示乙個訊號。這種定義方式和檔案描述符fd_set類似。linux提供一組函式來設定、修改、刪除和查詢訊號集

#include

intsigemptyset

(sigset_t* _set)

// 清空訊號集

intsigfillset

(sigset_t* _set)

// 在訊號集中設定所有訊號

intsigaddset

(sigset_t* _set,

int _signo)

// 將訊號_signo新增至訊號集中

intsigdelset

(sigset_t* _set,

int _signo)

//將訊號_signo從訊號集中刪除

intsigismember

(_const sigset_t* _set,

int _signo)

// 測試_signo是否在訊號集中

可以利用sigaction結構體的sa_mask成員來設定程序的訊號掩碼。

此外,下方的函式也可以用於設定或檢視程序的訊號掩碼

#include

intsigprocmask

(int _how, _const sigset_t* _set, sigset_t* _oset)

;

_set引數指定新的訊號掩碼,_oset引數則輸出原來的訊號掩碼(如果不為null),則_how引數指定設定程序訊號掩碼的方式。

_how引數

含義sig_block

新的程序訊號掩碼是其當前值和,_set指定訊號集的並集

sig_unblock

_set指定的訊號集將不被遮蔽

sig_setmask

直接將程序訊號掩碼設定為_set

如果_set為null,則程序掩碼不變,此時我們仍然可以利用_oset引數來獲得程序當前的訊號掩碼。

sigprocmask成功時返回0,失敗時返回-1,並設定errno。

如果給程序傳送被遮蔽的訊號,則作業系統將該訊號設定為程序的乙個被掛起的訊號。如果我們取消對被掛起訊號的遮蔽,則它能立即被程序接收到。

#include

intsigpending

(sigset_t* set)

;

要注意的點,set中存放的可能是被多次接收到的遮蔽訊號,最終只進行一次處理。

我們不能設想新建立的程序、執行緒具有和父程序、主線程完全相同的訊號特徵。

sighub

sigpipe

sigurg

struct sigaction

__sigaction_handler;

# define sa_handler __sigaction_handler.sa_handler

# define sa_sigaction __sigaction_handler.sa_sigaction

#else

__sighandler_t sa_handler;

#endif

/* additional set of signals to be blocked. */

__sigset_t sa_mask;

/* special flags. */

int sa_flags;

/* restore handler. */

void

(*sa_restorer)

(void);

};

Linux系統程式設計 訊號

0x00 訊號和中斷類似,中斷是硬體發出,而訊號由軟體發出。訊號常用於程序間通訊,乙個訊號常見的處理如下 1 設定對應訊號的訊號處理函式。2 當訊號來臨時,打斷正常執行的程式 本質上是在系統呼叫前檢查是否有訊號的到來 去執行訊號處理函式。3 訊號處理函式執行完,繼續執行原程式。0x01 我們先來看一...

Linux系統程式設計 訊號

基本概念 訊號的狀態 產生未決狀態 沒有被處理的 遞達 已經被處理的 訊號的優先順序比較高 程序收到訊號之後,暫停正在處理的工作 訊號集 kill 發射訊號給某個程序 raise 自己給自己發訊號 函式原型 int raise int sig abort 給自己傳送異常終止的訊號 alarm 設定定...

Linux系統程式設計 訊號

訊號的共性 1.簡單 2.不能攜帶大量資訊 3.滿足特定條件才能傳送 訊號的機制 1.訊號是軟體層面的中斷。一旦訊號產生,無論程式執行到什麼位置都必須結束 2.所有訊號的產生以及處理都是核心產生.訊號的產生 1.按鍵產生 程ctrl c ctrl v 2.系統呼叫產生 kill函式 3.定時器 al...