Tutorial Study Image

C++ 信号处理


2023年6月14日, Learn eTutorial
1160

操作系统发送给进程的信号是中断,它们有能力提前结束一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上,按 Ctrl+C 会导致中断。被称为信号的中断会迫使操作系统暂停其当前任务,以便处理发送中断的任务。任何操作系统软件都可能因这些中断而服务暂停。同样,C++ 提供了各种可以被程序处理的信号。

信号处理函数的作用是什么?

信号处理函数只是一个与程序其余部分一起编译的函数。您可以使用 signal 或 sigaction 指示操作系统在收到信号时调用一个函数,而无需显式调用它。

C++ 用户可以处理以下众多信号及其操作列表。

信号 操作

SIGINT

 

创建已激活信号的收据

 

SIGTERM

 

发送终止程序的请求。

 

SIGBUS

 

总线错误指示了对错误地址的访问。

SIGILL

查找了不允许的命令

 

SIGALRM

 

这作为计时器即将到期的提醒,并由 alarm() 函数使用。

SIGABRT

意外发生的程序终止

 

SIGSTOP

 

该信号有能力停止一个进程,且无法被阻止、处理或忽略。

SIGSEGV

 

无效存储访问

SIGFPE

 

溢出或数学上不正确的操作,例如除以零。

SIGUSR1

 

这些是用户定义的信号

SIGSUR2

 

这些是用户定义的信号

 

Signal() 函数

C++ 信号处理包中的 signal() 函数可用于捕获意外的中断或事件。这意味着信号库的 signal() 函数可用,并用于捕获不需要的中断或事件。

语法


signal(registered signal, signal handler)
 

void (*signal (int sig, void (*func)(int)))(int);  
 

这里的第一个参数是一个表示信号编号的整数,第二个参数是指向处理信号的函数的指针。我们需要记住,要捕获的信号需要使用 signal 函数进行注册,并连接到信号处理函数。信号处理函数需要是 void 类型。

  • 返回值:此函数的返回类型和参数类型 func 相同。如果函数的请求成功,它将提供一个指向在调用之前负责处理此信号的特定处理函数的指针(如果有)。
  • 数据竞争:未定义数据竞争。如果在多线程程序中调用此函数,将导致未定义行为。
  • 异常:切勿在此函数中抛出异常。

用于演示 signal() 函数的 C++ 程序


#include <csignal>
#include <iostream>
using namespace std;

void signal_handler(int signal_num)
{
 cout << "The interrupt signal is (" << signal_num
  << "). \n";

 // It will terminates the program
 exit(signal_num);
}

int main()
{
 // register the signal SIGABRT as well as signal handler
 signal(SIGABRT, signal_handler);

 while (true)
  cout << "Hai and Hello learnEtutorials..." << endl;
 return 0;
}

 

输出


Hai and Hello learnEtutorials...
Hai and Hello learnEtutorials...
Hai and Hello learnEtutorials...
Hai and Hello learnEtutorials...

输出:由于此代码处于无限循环中,因此它将显示上述输出,直到发生中断。

现在,如果我们使用 Ctrl+C 发送中断,程序将打印以下消息并结束。

输出


Hai and Hello learnEtutorials...
Hai and Hello learnEtutorials...
Hai and Hello learnEtutorials...
Hai and Hello learnEtutorials...
The interrupt signal is (22).

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 << "The Signal is handled";  
    else  
        cout << "The Signal is not handled";  
  
    return 0;  
}  
 

输出


The Signal is handled

raise() 函数

要将信号发送到当前运行的应用程序,需要使用 C++ signal raise() 函数。raise() 函数在 <csignal> 头文件中指定,用于处理特定信号。

语法


int raise (int sig);  
 

参数

sig:需要发送以进行处理的信号。它可以具有以下值

  • SIGINT
  • SIGABRT
  • SIGFPE
  • SIGILL
  • SIGSEGV
  • SIGTERM
  • SIGHUP

返回值

成功时返回零,失败时返回非零。

数据竞争

可以同时调用此函数而不会触发任何数据竞争。

异常

当引发信号且未分配处理函数来处理它时,此函数永远不会抛出异常。

示例 1

为了演示 raise() 函数在传递 SIGABRT 时如何使用,让我们看一个简单的例子

使用 SIGABRT 的示例程序


#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 the signal handler is called" << endl;  
    cout << "Signal = " << sig_value << endl;   
    raise(SIGABRT);  
    cout << "After the signal handler is called" << endl;  
    cout << "Signal = " << sig_value << endl;  
  
    return 0;  
}  
 

输出


Before the signal handler is called
Signal = 0
After the signal handler is called
Signal = 6

示例 2

为了演示 raise() 函数在提供 SIGINT 时如何使用,让我们看一个简单的例子

使用 SIGINT 的示例程序


#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 the called Signal = " << s_value << endl;   
    raise(SIGINT);   
    cout << "After the called Signal = " << s_value << endl;   
    return 0;   
}  

 

输出


Before the called Signal = 0
After the called Signal = 2

示例 3

作为如何使用 raise() 函数在提供 SIGTERM 时的方法,让我们看一个简单的例子

使用 SIGTERM 的示例程序


#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 the called Signal = " << s_value << endl;   
    raise(SIGTERM);   
    cout << "After the called Signal = " << s_value << endl;   
    return 0;   
}  

 

输出


Before the called Signal = 0
After  the called Signal = 15