Namespaces
Variants

std:: signal

From cppreference.net
Utilities library
定义于头文件 <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 - 要设置信号处理程序的信号。可以是实现定义的值或以下值之一:
定义信号类型
(宏常量)
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