2011-02-27 26 views
3

我想运行一段代码,但可以选择在完全完成之前中断它(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);}; 

除了我只想杀死子进程。

这是解决我的问题的正确思路吗?如果是这样,需要进行哪些信号处理才能使其工作?

UPDATE:
为了更彻底地解决我的问题我研究建议非分叉的方法。没有叉子,我应该可以做到这一点似乎是合理的。不幸的是,我现在停留在几次尝试中的编译错误上。我已经包含更新的代码和新的错误。

在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)'
在管理器中调用signal(SIGINT,sighandler) ::运行()来设置处理程序。

如果我打电话的printList()在静态sighandler功能我得到这个:
error: cannot call member function 'void Manager::PrintList()' without object
在sighandler的PrintList();()调用。

最后我注意到,使PrintList()是一个静态函数(带有一个静态sighandler),我得到这些错误列表和迭代器遍历列表。
error: invalid use of member 'Manager::theList' in static member function
error: invalid use of member 'Manager::it' in static member function

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

+1

我认为你应该在单独的问题中提出你的信号问题。如果您接受原始问题的答案,则可能更有可能得到回答。 – 2011-03-01 02:22:43

回答

2

根据您希望中断的功能,这可能无需分叉即可实现。

如果函数在循环中进行处理,信号处理程序可以设置一个布尔值,指示您想要处理停止。循环可以检查这个布尔值,并且一旦它由信号处理程序设置,函数就可以安全地退出并保持一致的状态。

+0

好点 - 我的答案假定他想要多个进程(或线程)出于其他原因,但如果它只是用于可中断性,那么信号处理程序和全局布尔值就更简单了。 – 2011-02-27 20:49:23

+0

谢谢,我错误地说服了我自己认为我需要一把叉子。 – niwals 2011-03-01 18:20:14

2

除非你明确地共享内存(比如mmap),否则你的孩子不会产生你可以看到的结果。假设你修复了这个问题,你可以用signal(SIGINT, SIG_IGN)来忽略父项中的​​ctrl-C(在fork之前),然后在signal(SIGINT, SIG_DFL)的子项中将它重置为默认值。

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

上忽略SIGINT的说明:这惹恼你在某些时候,当你只是想杀死你的整个应用程序,现在CTRL-C并没有做任何事情。不可避免地,我发现自己诅咒这样的应用程序,因为我找到了杀死它们的其他方法(按Ctrl- \发送SIGQUIT或Ctrl + Z + kill)。

+0

“该处理程序需要设置一些对BuildList()的内部循环可见的变量,以便它可以正常终止”。如果你以这种方式使用线程,你可以使用信号处理程序中的'pthread_cancel'和内部循环中的'pthread_testcancel',以避免滚动你自己的机制?我担心'pthread_cancel'不是信号安全的,但我想这不是一个很大的机制。 – 2011-02-27 22:59:42

+0

无论你做什么,你都不想在'BuildList()'中泄漏资源,这听起来像一个分配内存的函数。即使将可取消性类型设置为“PTHREAD_CANCEL_DEFERRED”,除了明确的“pthread_testcancel”之外,还有几个取消点。有可能有办法解决这个问题 - 我没有在玩具应用程序之外使用'pthread_cancel'。 – 2011-02-27 23:39:23

+0

够公平的,虽然'malloc'不包含取消点,所以它取决于这个列表将如何建立。通常,其他取消点是阻止很长时间的事情,所以您希望*它们在那里用于取消超时,如果您在设置时阻止了标记,则检查标记可能是不充分的。我认为,取消线程可能是其中一件不值得使用的东西,除非你正确地学习它们,包括陷阱,那么它们才有意义。我记得您可以通过切换日志记录意外地将取消点引入不可取消的代码。 – 2011-02-28 00:24:17

相关问题