std::signal

来自cppreference.com
< cpp‎ | utility‎ | program
 
 
工具库
通用工具
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中弃用)
整数比较函数
(C++20)(C++20)(C++20)
(C++20)
swap 与类型运算
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
常用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
初等字符串转换
(C++17)
(C++17)
 
程序支持工具
程序终止
(C++11)
(C++11)
不可达控制流
与环境交流
信号
信号类型
非局部跳转
类型
 
在标头 <csignal> 定义
/* 信号处理函数类型 */* signal( int sig, /* 信号处理函数类型 */* handler );
(1)
extern "C" using /* 信号处理函数类型 */ = 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);
void fun(int sig);
(C++17 起)

返回值

成功时返回先前的信号处理函数,失败时返回 SIG_ERR(某些实现上能禁用设置信号处理函数)。

信号处理函数

下列限制被加诸被安装为信号处理函数的用户定义函数。

普通免锁不可分割操作 是满足以下条件之一的对来自 <atomic><stdatomic.h> (C++23 起) 的函数 f 的调用:

如果任何信号处理函数进行任何下列操作,那么行为未定义:

  • 调用任何库函数,除非该调用是普通免锁不可分割操作,或者调用的是下列信号安全函数(尤其注意动态分配函数不是信号安全的):
  • 访问拥有线程存储期的对象
  • dynamic_cast 表达式
  • throw 表达式
  • 进入 try 块,包含函数 try
  • 初始化进行动态非局部初始化的静态变量(包含延迟直至首次 ODR 使用者)
  • 等待任何有静态存储期变量的初始化完成,由于另一线程共时初始化之

}}

如果信号处理函数不作为 std::abortstd::raise(异步信号)的结果调用,那么在以下情况下行为未定义:

  • 信号处理函数调用任何标准库中的函数,除了
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal,以当前处理的信号的数字作为第一个参数(异步处理函数能重注册它自身,但不能注册其他函数)。
  • 信号处理函数涉及任何拥有静态存储期的对象,且它的类型不是 std::atomic (C++11 起) volatile std::sig_atomic_t
(C++17 前)
(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++ 链接的函数能否用作信号处理函数由实现定义。

(C++17 前)

不限制信号处理函数的链接。

(C++17 起)

示例

#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 << "信号值:" << gSignalStatus << '\n';
    std::cout << "发送信号 " << SIGINT << '\n';
    std::raise(SIGINT);
    std::cout << "信号值:" << gSignalStatus << '\n';
}

可能的输出:

信号值:0
发送信号 2
信号值:2

引用

  • C++23 标准(ISO/IEC 14882:2023):
  • 17.13.5 Signal handlers [support.signal]
  • C++20 标准(ISO/IEC 14882:2020):
  • 17.13.5 Signal handlers [support.signal]
  • C++17 标准(ISO/IEC 14882:2017):
  • 21.10.4 Signal handlers [support.signal]

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 3756 C++17 不明确 std::atomic_flag 是否信号安全 它是信号安全的

参阅

为特定信号运行信号处理函数
(函数)
线程与执行于同一线程的信号处理函数间的栅栏
(函数)