Namespaces
Variants

std::signal

来自 zh.cppreference.net
 
 
 
 
在头文件 <csignal>
/*signal-handler*/* signal( int sig, /*signal-handler*/* handler );
中定义 (1)
extern "C" using /*signal-handler*/ = void(int);
(2) (*仅供说明)

更改信号 sig 的处理方式。根据 handler 的值,信号可以被忽略、设为默认处理,或由用户定义的函数以 (*handler)(sig) 形式调用处理。

当信号处理函数被设置为某个函数且信号发生时,std::signal(sig, SIG_DFL) 是否在信号处理函数开始前立即执行是由实现定义的。此外,实现可以阻止某些由实现定义的一组信号在处理函数运行期间发生。

对于某些信号,实现可能会在程序启动时调用 std::signal(sig, SIG_IGN)。对于其余信号,实现必须调用 std::signal(sig, SIG_DFL)。

(注意:POSIX 引入了 sigaction 来标准化这些由实现定义的行为。)

参数

sig - 要为其设置信号处理程序的信号。它可以是由实现定义的值,也可以是以下值之一:
定义信号类型
(宏常量)
handler - 信号处理程序。它必须是以下之一:
  • SIG_DFL 宏。信号处理程序被设置为默认信号处理程序。
  • SIG_IGN 宏。该信号被忽略。
  • 指向函数的指针。该函数的签名必须等同于以下形式:
extern "C" void fun(int sig);

返回值

成功时返回先前的信号处理器,失败时返回 SIG_ERR (在某些实现中设置信号处理器可能被禁用)。

信号处理器

作为信号处理程序安装的用户自定义函数需遵循以下限制。

若信号处理器的调用并非源自 std::abort 或 std::raise (异步信号),则在以下情况下行为未定义:

  • 信号处理器调用标准库中的任何函数,除了:
(until C++17)

纯无锁原子操作 是指调用来自 <atomic> 或 <stdatomic.h> (since C++23) 的函数 f ,且满足以下条件之一:

若任何信号处理器执行以下任一操作,则行为未定义:

  • 调用任何库函数,除了纯无锁原子操作及以下 信号安全 函数(特别注意,动态分配非信号安全):
  • 访问具有线程存储期的对象
  • dynamic_cast 表达式
  • throw 表达式
  • 进入 try 块
  • 执行 动态非局部初始化 的静态变量初始化(包括延迟至首次 ODR 使用)
  • 等待由于其他线程并发初始化而导致的任何具有静态存储期变量的初始化完成
(since C++17)

如果用户定义函数在处理 SIGFPE 、 SIGILL 、 SIGSEGV 或任何其他指定计算异常的实现定义信号时返回,则行为是未定义的。

如果信号处理函数是由于 std::abort 或 std::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()
{
    // 安装信号处理器
    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