中断方法但继续执行代码的其余部分

时间:2011-02-27 20:27:01

标签: c++ signals

我想运行我的代码的一部分,但可以选择在它完全完成之前中断它(ctrl-c)并继续执行我的其余代码。 (我正在Linux平台上工作。)

我的猜测是创建fork,调用方法,然后使用信号处理。信号处理需要哪些步骤?

void Manager::Run()
{
    pid_t pID = fork();

    if( pID<0 )
        exit(1);//give up here
    else if( pID==0 ) {            
        BuildList(); //I'd like the option to ctrl-c this only
        //some code here catch user signal interrupt?
    }
    else {;}

    waitpid(pID,NULL,0);//pause until BuildList() is done or interrupted


    PrintList();
}

看起来我想在if / else部分的某个地方使用像signal(SIGINT,sigint)这样的行。我需要定义一个这样的函数:

sigint(int param){ signal(param, SIG_DFL);};

除了我只想杀死子进程。

这是解决我问题的正确方法吗?如果是这样,需要什么信号处理才能使其工作?

更新
为了更完整地解决我的问题,我探索了建议的非分叉方法。没有分叉我应该能做到这一点似乎是合理的。不幸的是,我现在因为我的一些尝试而陷入编译错误。我已经包含了更新的代码和新的错误。

在Manager.hh中

    static void sighandler(int signum)
    {
        PrintList();
        exit(1);
    };

Manager.cc包含

void Manager::Run()
{
    signal(SIGINT,sighandler);//sets up sighandler()
    BuildList(); //add elements to a list
    signal(SIGINT,SIG_DFL);   //restore default 
    PrintList();  
}

如果sighandler功能不是静态的,我得到这个:
error: argument of type 'void (Manager::)(int)' does not match 'void (*)(int)'
在Manager :: Run()的调用signal(SIGINT,sighandler)上设置处理程序。

如果我在静态sighandler函数中调用PrintList(),我得到这个:
error: cannot call member function 'void Manager::PrintList()' without object
在sighandler()的PrintList();调用中。

最后我注意到使PrintList()成为静态函数(使用静态sighandler),我在List和迭代器上得到这些错误以逐步浏览列表。
error: invalid use of member 'Manager::theList' in static member function
error: invalid use of member 'Manager::it' in static member function

解决这些错误的任何聪明方法?

2 个答案:

答案 0 :(得分:2)

根据您希望中断的功能,可以在不分叉的情况下实现。

如果函数在循环中进行处理,则信号处理程序可以设置一个布尔值,表示您希望处理停止。循环可以只检查这个布尔值,一旦信号处理程序设置,函数就可以安全地退出并保持一致状态。

答案 1 :(得分:2)

除非你明确地分享记忆(比如说mmap),否则你的fork孩子不会产生你能看到的结果。假设您已修复此问题,您可以signal(SIGINT, SIG_IGN)忽略父级中的ctrl-C(fork之前),然后将其重置为signal(SIGINT, SIG_DFL)的子级中的默认值。

如果你改用线程(简化内存共享),那么答案就会改变:SIGINT是一个异步信号,这意味着它不是由于执行一条指令而产生的。特定线程(相反,SIGSEGV是同步信号)。在线程应用程序中,所有线程都有一个共享信号处理程序。对于异步信号,它可以传递给任何线程。该处理程序需要将一些变量设置为BuildList()的内部循环,以便它可以正常终止。

关于忽略SIGINT的注意事项: 我不可避免地发现自己在诅咒这些应用程序,因为我找到了其他方法来杀死它们(ctrl- \发送SIGQUIT或ctrl-Z + kill)。