【问题标题】:Override Ctrl-C覆盖 Ctrl-C
【发布时间】:2011-10-01 22:35:16
【问题描述】:

我应该覆盖 CtrlC 信号并使用它来打印消息。它不应该结束程序。

到目前为止发生的情况是,当按下 CtrlC 时,它会打印消息,但会结束程序。

当我问我的教授时,他告诉我这样做: 您需要让您的信号处理程序不再继续处理信号。现在信号正在由您的代码处理,然后转到父处理程序。

是否有我应该添加的方法或者我需要将信号安装程序移动到某个地方?

这是我目前的代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>  
#include <sys/types.h>
#include <signal.h> 
#include "Input.h"
#include "CircleBuff.h"

//void handler_function(int signal_id);

void catch_int(int sig_num){

    //reset the signal handler again to catch_int, for next time
    signal(SIGINT, catch_int);
    //print message
    printf("Print History");
    fflush(stdout);
}

void printHistory(CircleBuff hist){
    cout << "Complete History:\n" << endl;
    hist.print();
    cout << endl;
}

int main(int argc, char** argv){

  struct sigaction signal_action;                /* define table */
  signal_action.sa_handler = catch_int;   /* insert handler function */
  signal_action.sa_flags = 0;                    /* init the flags field */
  sigemptyset( &signal_action.sa_mask );     /* are no masked interrupts */
  sigaction( SIGINT, &signal_action, NULL ); /* install the signal_action */

  do{


  //My code: where the value report will be assigned within.

  } while(report != 1)

}

【问题讨论】:

  • 您不应该从信号处理程序内部调用printf,因为printf 不是异步安全的。有关异步安全函数的列表,请参阅 man 7 signal。更简单的 write 系统调用是异步安全的,但 &lt;stdio.h&gt; 函数都不是。

标签: c++ c linux signals


【解决方案1】:

哇,方式太多代码无法筛选。但是,如果您使用 C 标准库,您应该获得所需的行为。这是一个 C++ 版本:

#include <iostream>
#include <csignal>

sig_atomic_t sigflag = 0;

void sighandler(int s)
{
  // std::cerr << "Caught signal " << s << ".\n"; // this is undefined behaviour
  sigflag = 1; // something like that
}

int main()
{
  std::signal(SIGINT, sighandler);

  // ... your program here ...

  // example: baby's first loop (Ctrl-D to end)
  char c;
  while (std::cin >> c)
  {
    if (sigflag != 0) { std::cerr << "Signal!\n"; sigflag = 0; }
  }
}

这将捕获Ctrl-C(引发SIGINT),并且信号处理程序不会被替换,因此它每次都会触发,并且没有人终止程序。

请注意,信号处理程序由fork()ed 子代继承。

Posix 函数sigaction() 允许您注册“一次性”处理程序,这些处理程序在被调用一次后会被标准处理程序替换。不过,这更高级且特定于 Posix。

编辑: 正如@Dietrich 指出的那样,您永远不应该在信号处理程序内部做任何真正的工作。相反,您应该设置一个标志(我提供了一个示例),并在循环中检查该标志(并在那里打印消息)。我也会为此修改示例。

【讨论】:

  • 在信号处理程序中使用std::cerr是非常不安全的。
  • @DietrichEpp:不安全或不可预测?可能发生的最坏情况是什么?当然正确的做法是设置一个标志并继续前进,但这会使示例复杂化。不过我会记下。
  • 感谢您的意见。我会尝试这个选项,不幸的是教授希望我们使用 c 方法处理信号。 (我还缩短了代码,只包含重要的材料)
  • @ensantos91:在 C 语言中它实际上是相同的,只是减去了 std::。另外,如果你不想谈论C++,你为什么要标记这个C++??
  • 不安全,因为您可以同时在主线程中使用cerr,并且两者都可以读取和修改cerr 缓冲区的状态。我希望这样做的程序充其量会表现出罕见的意外行为和崩溃,最坏的情况是会造成严重的安全漏洞。 (服务器中设计不良的信号处理程序会导致许多已知的安全漏洞。)
【解决方案2】:

您是否考虑过在您的 while 循环中可能有一个可中断函数因“EINTR”而失败。您可以使用以下方法修复它:

sa.sa_flags = SA_RESTART;

或者,只是检查 errno 并循环。你确定程序没有达到终止的终点吗?尝试在 main 的末尾添加一个 print 语句。

【讨论】:

    猜你喜欢
    • 2012-03-18
    • 1970-01-01
    • 2010-11-23
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2015-05-13
    相关资源
    最近更新 更多