中断一个方法但继续执行剩余的代码
我想运行我的代码的一部分,但可以选择在它完全完成之前中断它(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();
}
如果ighandler函数不是静态的我得到这个:错误:“void (Manager::)(int)”类型的参数与“void (*)(int)”不匹配
在 Manager::Run() 中调用 signal(SIGINT,sighandler)
来设置处理程序。
如果我在静态ighandler函数中调用PrintList(),我会得到:错误:无法在没有对象的情况下调用成员函数“void Manager::PrintList()”
在ighandler() 中的PrintList();
调用上。
最后,我注意到,将 PrintList() 设为静态函数(使用静态叹号处理程序),我会在列表和迭代器中得到这些错误以逐步浏览列表。错误:在静态成员函数中无效使用成员“Manager::theList”
错误:在静态成员函数中无效使用成员“Manager::it”
有什么巧妙的方法可以解决这些错误吗?
I want to run a section of my code but with the option to interrupt it (ctrl-c) before it is completely done and resume executing the rest of my code. (I am working on a Linux platform.)
My guess is to create fork, call the method, and then use signal handling. What steps are needed for the signal handling?
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();
}
It looks like I would want to use a line like signal(SIGINT,sigint) somewhere in if/else part. And I would need to define a function like this:
sigint(int param){ signal(param, SIG_DFL);};
Except I only want to kill the child process.
Is this the right idea to solve my problem? If so, what signal handling is needed to make this work?
UPDATE:
To more completely address my question I explored the suggested non-forking methods. It seems reasonable that I should be able to do this without the fork. Unfortunately, I am now stuck on compile errors from a few of my attempts. I have included the updated code and new errors.
in Manager.hh
static void sighandler(int signum)
{
PrintList();
exit(1);
};
Manager.cc contains
void Manager::Run()
{
signal(SIGINT,sighandler);//sets up sighandler()
BuildList(); //add elements to a list
signal(SIGINT,SIG_DFL); //restore default
PrintList();
}
If the sighandler function is not static I get this:error: argument of type 'void (Manager::)(int)' does not match 'void (*)(int)'
on the call signal(SIGINT,sighandler)
in Manager::Run() to set up the handler.
If I call PrintList() in a static sighandler function I get this:error: cannot call member function 'void Manager::PrintList()' without object
on the PrintList();
call in sighandler().
Lastly I note that making PrintList() a static function (with a static sighandler), I get these errors on the List and the iterator to step through the list.error: invalid use of member 'Manager::theList' in static member function
error: invalid use of member 'Manager::it' in static member function
Any clever ways around these errors?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据您希望中断的功能,这可能无需分叉即可实现。
如果函数在循环中进行处理,则信号处理程序可以设置一个布尔值,指示您希望停止处理。循环可以只检查这个布尔值,并且一旦信号处理程序设置了该布尔值,该函数就可以安全地并以一致的状态退出。
Depending on the function you wish to interrupt, this might be implemented without forking.
If the function doing its processing in a loop, the signal handler can set a boolean indicating you want processing to stop. The loop can just check this boolean and the function can exit safely and in a consistent sate once it's set by the signal handler.
除非您显式共享内存(例如使用
mmap
),否则您的fork
子级将不会产生您可以看到的结果。假设您解决了这个问题,您可以signal(SIGINT, SIG_IGN)
忽略父级中的ctrl-C(在fork
之前),然后在子级中将其重置回默认值信号(SIGINT,SIG_DFL)
。如果您改用线程(以简化内存共享),那么答案就会改变:
SIGINT
是一个异步信号,这意味着它不是由执行 a 中的指令而产生的。特定线程(相反,SIGSEGV 是同步信号)。在线程应用程序中,所有线程都有一个共享的信号处理程序。对于异步信号,它可以传递到任何线程。该处理程序需要设置一些对 BuildList() 的内部循环可见的变量,以便它可以正常终止。关于忽略
SIGINT
的注意事项:当您只想终止整个应用程序而现在 ctrl-C 不执行任何操作时,它会让您烦恼。我不可避免地发现自己在咒骂这些应用程序,因为我找到了其他方法来杀死它们(ctrl-\发送SIGQUIT
,或ctrl-Z +kill
)。Unless you are explicitly sharing memory (say with
mmap
) then yourfork
child is not going to produce results you can see. Assuming you fixed that, you couldsignal(SIGINT, SIG_IGN)
to ignore ctrl-C in the parent (beforefork
) and then reset it back to default in the child withsignal(SIGINT, SIG_DFL)
.If you use threads instead (to simpilfy the memory sharing) then the answer changes:
SIGINT
is an asynchronous signal, meaning it does not arise from the execution of an instruction in a particular thread (in contrast,SIGSEGV
is a synchronous signal). In a threaded application there is one shared signal handler for all threads. For asynchronous signals it could be delivered to any of your threads. That handler would need to set some variable visible to the inner loop ofBuildList()
so it could terminate gracefully.A note on ignoring
SIGINT
: It will annoy you at some point when you just want to kill your whole application and now ctrl-C doesn't do anything. Inevitably I find myself cursing such applications as I find other ways to kill them (ctrl-\ to sendSIGQUIT
, or ctrl-Z +kill
).