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 设置处理函数。可设置信号处理函数以令默认处理发生、信号被忽略或用户定义函数得到调用。

当信号处理函数被设为函数,且信号发生时,在信号处理函数开始之前是否立即执行 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::abortstd::raise (异步信号)的结果调用,则行为未定义,若

  • 信号处理函数调用任何标准库中的函数,除了
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal ,以当前处理的信号的数字为首参数(异步处理函数能重注册其自身,但不能注册其他函数)。
  • 信号处理函数涉及任何拥有静态或线程局域(C++11 起)存储期的对象,且其类型不是 std::atomic(C++11 起)volatile std::sig_atomic_t.
(C++17 前)

若任何信号处理函数进行任何下列操作,则行为未定义:

  • 调用任何库函数,除了下列信号安全函数(注意,尤其是动态分配函数不是信号安全的):
  • std::atomic 的成员函数和来自 <atomic> 的非成员函数,若它们所操作的原子类型是免锁的。函数 std::atomic_is_lock_freestd::atomic::is_lock_free 对所有原子类型信号安全。
  • std::signal ,以当前处理的信号的数字为首参数(异步处理函数能重注册其自身,但不能注册其他函数)。
  • std::numeric_limits 的函数
  • std::_Exit
  • std::abort
  • std::quick_exit
  • std::initializer_list 的成员函数及 std::beginstd::endstd::initializer_list 重载
  • std::forwardstd::movestd::move_if_noexcept
  • 所有来自 <type_traits> 的函数
  • std::memcpystd::memmove
  • 访问拥有线程存储期的对象
  • dynamic_cast 表达式
  • throw 表达式
  • 进入 try 块,包含函数 try 块
  • 初始化进行动态非局部初始化的静态变量(包含延迟直至首次 ODR 使用者)
  • 等待任何有静态存储期变量的初始化完成,由于另一线程共时初始化之
(C++17 起)

若在处理 SIGFPESIGILLSIGSEGV 或任何实现定义的指定计算性异常的其他信号时,用户定义函数返回,则行为未定义。

若信号处理函数作为 std::abortstd::raise (异步调用)的结果调用,则行为未定义,若信号处理函数调用 std::raise

在信号处理函数入口,浮点环境的状态和所有对象的值都是未指定的,除了

  • volatile std::sig_atomic_t 类型对象
  • 无锁 std::atomic 类型对象(C++11 起)
  • 通过 std::atomic_signal_fence 设为可见的副效应(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

[编辑] 参阅

为特定信号运行信号处理函数
(函数) [编辑]
signalC 文档
线程与执行于同一线程的信号处理函数间的栅栏
(函数) [编辑]