C++教程-C++信号处理

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):信号被忽略,即使不是有意为之,代码执行也将继续。
- 函数处理程序:定义了处理信号的特定函数。
我们必须记住,我们想要捕获的信号必须使用signal函数进行注册,并且它必须与信号处理函数相关联。
注意:信号处理函数应该是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()
{
// 安装信号处理函数
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;
kotlinCopy code
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