名稱空間
變體
操作

std::signal

來自 cppreference.com
< cpp‎ | utility‎ | program
 
 
 
 
定義於標頭檔案 <csignal>
/* signal-handler */* signal( int sig, /* signal-handler */* handler );
(1)
extern "C" using /* signal-handler */ = void(int);
(2) (僅作說明*)

改變訊號 sig 的處理方式。根據 handler 的不同,訊號可以被忽略,設定為預設處理,或者由使用者定義函式處理。

當訊號處理程式被設定為一個函式並且訊號發生時,在訊號處理程式開始之前是否立即執行 std::signal(sig, SIG_DFL) 是實現定義的。此外,實現可以在訊號處理程式執行時阻止某些實現定義的訊號集發生。

對於某些訊號,實現可以在程式啟動時呼叫 std::signal(sig, SIG_IGN)。對於其餘訊號,實現必須呼叫 std::signal(sig, SIG_DFL)

(注意:POSIX 引入了 sigaction 來標準化這些實現定義的行為)

目錄

[編輯] 引數

sig - 要設定訊號處理程式的訊號。它可以是實現定義的值或以下值之一
定義訊號型別
(宏常量) [編輯]
處理程式 - 訊號處理程式。這必須是以下之一
  • SIG_DFL 宏。訊號處理程式設定為預設訊號處理程式。
  • SIG_IGN 宏。訊號被忽略。
  • 指向函式的指標。函式的簽名必須等同於以下
extern "C" void fun(int sig);


[編輯] 返回值

成功時返回先前的訊號處理程式,失敗時返回 SIG_ERR(在某些實現上可能停用設定訊號處理程式)。

[編輯] 訊號處理程式

對作為訊號處理程式安裝的使用者定義函式施加以下限制。

如果訊號處理程式被呼叫不是因為 std::abortstd::raise(非同步訊號),則在以下情況下行為是未定義的:

  • 訊號處理程式呼叫標準庫中的任何函式,除了
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal,其第一個引數是當前正在處理的訊號編號(非同步處理程式可以重新註冊自身,但不能註冊其他訊號)。
  • 訊號處理程式引用任何具有靜態儲存持續時間的物件,但不是 std::atomic(自 C++11 起)volatile std::sig_atomic_t 的物件。
(C++17 前)

“*純粹的無鎖原子操作*”是呼叫 <atomic><stdatomic.h>(自 C++23 起) 中的函式 f,使得

如果任何訊號處理程式執行以下任何操作,則行為是未定義的

  • 呼叫任何庫函式,除了純無鎖原子操作和以下 *訊號安全* 函式(請特別注意,動態分配不是訊號安全的)
  • 訪問具有執行緒儲存持續時間的物件
  • 一個 dynamic_cast 表示式
  • 一個 throw 表示式
  • 進入 try
  • 初始化執行動態非區域性初始化的靜態變數(包括延遲到首次 ODR-use)
  • 等待任何具有靜態儲存持續時間的變數的初始化完成,因為另一個執行緒正在同時初始化它
(C++17 起)

如果使用者定義函式在處理 SIGFPESIGILLSIGSEGV 或任何其他指定計算異常的實現定義訊號時返回,則行為未定義。

如果訊號處理程式是由於 std::abortstd::raise(同步訊號)而被呼叫的,則如果訊號處理程式呼叫 std::raise,則行為未定義。

進入訊號處理程式時,浮點環境的狀態和所有物件的值都是未指定的,除了

(C++11 起)

從訊號處理程式返回時,任何由訊號處理程式修改的非 volatile std::sig_atomic_t 或無鎖 std::atomic 物件的行為都是不確定的。

(直到 C++14)

呼叫函式 signal() 同步於任何由此導致的訊號處理程式呼叫。

如果訊號處理程式是由於呼叫 std::raise(同步)而執行的,則處理程式的執行 *序列在* std::raise 呼叫之後,*序列在* 其返回之前,並在與 std::raise 相同的執行緒上執行。其他訊號處理程式的執行與程式的其餘部分 *未序列*,並在未指定執行緒上執行。

對相同 volatile std::sig_atomic_t 型別物件的兩次訪問不會導致資料競爭,如果兩者都發生在同一執行緒中,即使其中一個或多個發生在訊號處理程式中。對於每個訊號處理程式呼叫,由呼叫訊號處理程式的執行緒執行的評估可以分為兩組 A 和 B,這樣 B 中的評估都不會 *先於* A 中的評估發生,並且這些 volatile std::sig_atomic_t 物件的評估取值就好像 A 中的所有評估都 先於 訊號處理程式的執行發生,並且訊號處理程式的執行 *先於* B 中的所有評估發生。

(C++14 起)

[編輯] 注意

POSIX 要求 `signal` 是執行緒安全的,並 指定了一系列可從任何訊號處理程式呼叫的非同步訊號安全庫函式

訊號處理程式預期具有 C 連結,並且通常只使用 C 和 C++ 公共子集中的功能。然而,常見的實現允許使用具有 C++ 連結的函式作為訊號處理程式。

[編輯] 示例

#include <csignal>
#include <iostream>
 
namespace
{
    volatile std::sig_atomic_t gSignalStatus;
}
 
void signal_handler(int signal)
{
    gSignalStatus = signal;
}
 
int main()
{
    // Install a signal handler
    std::signal(SIGINT, signal_handler);
 
    std::cout << "SignalValue: " << gSignalStatus << '\n';
    std::cout << "Sending signal: " << SIGINT << '\n';
    std::raise(SIGINT);
    std::cout << "SignalValue: " << gSignalStatus << '\n';
}

可能的輸出

SignalValue: 0
Sending signal: 2
SignalValue: 2

[編輯] 參考

  • C++23 標準 (ISO/IEC 14882:2024)
  • 17.13.5 訊號處理程式 [support.signal]
  • C++20 標準 (ISO/IEC 14882:2020)
  • 17.13.5 訊號處理程式 [support.signal]
  • C++17 標準 (ISO/IEC 14882:2017)
  • 21.10.4 訊號處理程式 [support.signal]

[編輯] 缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
LWG 3756 C++17 不清楚 std::atomic_flag 是否是訊號安全的 它是

[編輯] 參見

為特定訊號執行訊號處理程式
(函式) [編輯]
執行緒與在同一執行緒中執行的訊號處理程式之間的屏障
(函式) [編輯]
C 文件 關於 signal