C++ 信号处理
- 信号是由操作系统发送给进程的中断,用于停止进程正在进行的任务,并处理生成中断的任务。
- 信号也可以根据系统或错误条件由操作系统生成。
- 您可以通过在 Linux、UNIX、Mac OS X 或 Windows 系统上按下 Ctrl + C 来产生中断。
有一些信号无法被程序捕获,但以下是一系列您可以在程序中捕获并根据信号采取适当操作的信号列表。
这些信号在 <csingnal>
头文件中定义。
下面是信号列表以及它们的描述和工作能力:
信号 | 描述 |
---|---|
SIGABRT | (中断信号) 程序异常终止,例如调用 abort 函数。 |
SIGFPE | (浮点异常信号) 错误的算术操作,例如除零或导致溢出的操作。 |
SIGILL | (非法指令信号) 用于检测非法指令。 |
SIGINT | (中断信号) 用于接收交互式程序的中断信号。 |
SIGSEGV | (段错误信号) 对存储器的无效访问。 |
SIGTERM | (终止信号) 发送给程序的终止请求。 |
SIGHUP | (挂断信号) 挂断(POSIX),报告用户终端已断开连接。用于报告控制进程的终止。 |
SIGQUIT | 用于终止进程并生成核心转储。 |
SIGTRAP | 跟踪陷阱。 |
SIGBUS | 这是一个总线错误,表示对无效地址的访问。 |
SIGUSR1 | 用户定义的信号1。 |
SIGUSR2 | 用户定义的信号2。 |
SIGALRM | 闹钟信号,表示无效地址的访问。 |
SIGTERM | 用于终止。可以阻塞、处理和忽略此信号。由 kill 命令生成。 |
SIGCOUNT | 发送给进程的信号,用于使其继续运行。 |
SIGSTOP | 停止信号,不可阻塞。用于停止进程。无法处理、忽略或阻塞此信号。 |
signal()函数
C++信号处理库提供了signal函数来捕获意外中断或事件。
语法
void (*signal (int sig, void (*func)(int)))(int);
参数
此函数用于处理信号。
它指定了处理由 sig 指定的信号的方式。
func 参数指定了程序处理信号的三种方式之一。
- 默认处理(SIG_DFL): 由特定信号的默认操作处理该信号。
- 忽略信号(SIG_IGN): 信号被忽略,即使不是故意执行的代码也会继续执行。
- 函数处理程序: 定义了一个特定的函数来处理信号。
我们必须记住,我们想要捕捉的信号必须使用信号函数注册,并且必须与一个信号处理函数关联起来。
注意:信号处理函数应该是void类型。
返回值
此函数的返回类型与参数func的类型相同。
如果此函数的请求成功,函数将返回一个指向在调用之前负责处理该信号的特定处理程序函数的指针(如果有的话)。
数据竞争
数据竞争是未定义的。如果在多线程程序中调用此函数,则会导致未定义的行为。
异常
此函数不会引发异常。
示例1
让我们看一个简单的示例来演示signal()函数的用法:
#include <iostream>
#include <csignal>
using namespace std;
sig_atomic_t signalled = 0;
void handler(int sig)
{
signalled = 1;
}
int main()
{
signal(SIGINT, handler);
raise(SIGINT);
if (signalled)
cout << "Signal is handled";
else
cout << "Signal is not handled";
return 0;
}
输出:
Signal is handled
示例2
让我们看另一个简单的示例:
#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
raise()函数
C++信号raise()函数用于向当前执行的程序发送信号。
<csignal>
头文件声明了函数raise()用于处理特定的信号。
语法
int raise (int sig);
参数
sig: 要发送的信号号码进行处理。可以采取以下值之一:
- SIGINT
- SIGABRT
- SIGFPE
- SIGILL
- SIGSEGV
- SIGTERM
- SIGHUP
返回值
成功时,返回0;失败时,返回非零值。
数据竞争
并发调用此函数是安全的,不会造成数据竞争。
异常
此函数不会引发异常,如果没有使用signal定义函数处理所引发的信号。
示例1
让我们看一个简单的示例来说明当传递SIGABRT时使用raise()函数的用法:
#include <iostream>
#include <csignal>
using namespace std;
sig_atomic_t sig_value = 0;
void handler(int sig)
{
sig_value = sig;
}
int main()
{
signal(SIGABRT, handler);
cout << "Before signal handler is called" << endl;
cout << "Signal = " << sig_value << endl;
raise(SIGABRT);
cout << "After signal handler is called" << endl;
cout << "Signal = " << sig_value << endl;
return 0;
}
输出:
Before signal handler is called
Signal = 0
After signal handler is called
Signal = 6
示例2
让我们来看一个简单的示例,以说明当传递SIGINT时如何使用raise()函数:
#include <csignal>
#include <iostream>
using namespace std;
sig_atomic_t s_value = 0;
void handle(int signal_)
{
s_value = signal_;
}
int main()
{
signal(SIGINT, handle);
cout << "Before called Signal = " << s_value << endl;
raise(SIGINT);
cout << "After called Signal = " << s_value << endl;
return 0;
}
输出:
Before called Signal = 0
After called Signal = 2
示例3
让我们看一个简单的示例来说明在传递SIGTERM时使用raise()函数的用法:
#include <csignal>
#include <iostream>
using namespace std;
sig_atomic_t s_value = 0;
void handle(int signal_)
{
s_value = signal_;
}
int main()
{
signal(SIGTERM, handle);
cout << "Before called Signal = " << s_value << endl;
raise(SIGTERM);
cout << "After called Signal = " << s_value << endl;
return 0;
}
输出:
Before called Signal = 0
After called Signal = 15
示例4
让我们看一个简单的示例来说明在传递SIGSEGV时使用raise()函数的用法:
#include <csignal>
#include <iostream>
using namespace std;
sig_atomic_t s_value = 0;
void handle(int signal_)
{
s_value = signal_;
}
int main()
{
signal(SIGSEGV, handle);
cout << "Before called Signal = " << s_value << endl;
raise(SIGSEGV);
cout << "After called Signal = " << s_value << endl;
return 0;
}
输出:
Before called Signal = 0
After called Signal = 11
示例5
我们来看一个简单的示例,说明当SIGFPE被传递时使用raise()函数的方法:
#include <csignal>
#include <iostream>
using namespace std;
sig_atomic_t s_value = 0;
void handle(int signal_)
{
s_value = signal_;
}
int main()
{
signal(SIGFPE, handle);
cout << "Before called Signal = " << s_value << endl;
raise(SIGFPE);
cout << "After called Signal = " << s_value << endl;
return 0;
}
输出:
Before called Signal = 0
After called Signal = 8