C 使用信号来停止子进程
我当前的程序正在创建子进程并给它们工作(CPU 密集型工作)。 main() 坐在那里等待子进程通过管道发送数据(使用 select)。
我想做的是,当程序正在处理数据时,我可以按 CTRL+C 来停止子进程工作,并询问用户是否要退出或恢复工作。
如果用户想退出,程序将杀死所有进程。如果用户想恢复工作,它会告诉子进程恢复计算。
我已经有了代码,但它不太正常工作。
在 main 中,我有 signal(SIGINT, pausar);
来处理 SIGINT (CTRL+C)。
这是 pausar() 函数:
void pausar(int signum){
signal(SIGINT, pausar);
int i;
// pid[] contains all the child processes
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGSTOP);
}
char option[2];
printf("\n Computacao pausada.\n'S' para sair ou 'C' para continuar: ");
scanf("%1s", option);
if (option[0] == 's' || option[0] == 'S') {
printf("A desligar...\n");
//if user wants to quit, kill all the child processes
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGKILL);
}
exit(0);
}
else
{
printf("[%d] A resumir computacao...\n",getpid());
kill(getpid(), SIGCONT);
//if user wants to resume work, send signal to continue
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGCONT);
printf("%d resumiu\n", pid[i]);
}
}
}
问题是有时我按 CTRL+C 并且控制台中没有任何显示(但进程停止,因为我正在关注进程管理器)。另一个问题是,在我输入“C”恢复工作后,我在 select() 中收到错误,并且孩子们永远不会恢复工作。
My current program is creating child processes and giving them work (CPU intensive work). The main() sits there and waits for the child processes to send data via pipes (using select).
What I wanted to do is when the program is processing data I could press CTRL+C to stop the child processes from working and asking the user if he wants to quit or resume work.
If user wants to quit, the program would kill all the processes. If user wants to resume work, it would tell the child processes to resume the computation.
I already have the code in place but it's not quite working right.
In main I have signal(SIGINT, pausar);
to handle SIGINT (CTRL+C).
This is the pausar() function:
void pausar(int signum){
signal(SIGINT, pausar);
int i;
// pid[] contains all the child processes
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGSTOP);
}
char option[2];
printf("\n Computacao pausada.\n'S' para sair ou 'C' para continuar: ");
scanf("%1s", option);
if (option[0] == 's' || option[0] == 'S') {
printf("A desligar...\n");
//if user wants to quit, kill all the child processes
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGKILL);
}
exit(0);
}
else
{
printf("[%d] A resumir computacao...\n",getpid());
kill(getpid(), SIGCONT);
//if user wants to resume work, send signal to continue
for(i = 0; i<CORES; i++)
{
kill(pid[i], SIGCONT);
printf("%d resumiu\n", pid[i]);
}
}
}
The problem is that sometimes I press CTRL+C and nothing shows in the console (but the processes STOP because I'm paying attention to the process manager). The other problem is that after I enter 'C' to resume work, I get errors in select() and the children never resume work.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
同时使用
select()
和信号处理程序很容易出现竞争条件 - 在select()
调用期间可能会出现信号,但也可能在每行中出现代码。如果您使用的是 Linux:使用
signalfd()
并将此套接字添加到传递给
select()
的读取集中。然后,信号将在代码中的固定点进行处理,您无需担心竞争条件。Using
select()
and signal-handler at the same time is prone to race conditions - a signal could occur during theselect()
call, but also in every other line of code.If your are on linux: create an event socket with
signalfd()
and add this socket to the read set passed toselect()
. Signals are then handled at a fixed point in your code and you do not need to worry about race conditions.首先,对于您想要做的事情,您的信号处理程序太复杂了。其次,在信号处理程序中调用
signal()
不是一个好主意......它不是 异步信号安全函数。您可以执行以下操作:
signal()
设置信号处理函数。pselect()
之前到达。sig_atomic_t
pselect()
而不是select()
。这将允许您更改进程信号掩码以允许 SIGINT 信号到达,并且它将以相对于信号的原子方式执行此操作。否则,您的 SIGINT 可能会在调用select()
之前到达,然后您就“丢失”了该信号,即使它确实在处理程序中设置了标志。pselect()
调用返回时,检测该标志是否已设置。执行这些步骤将简化信号处理代码,并减少由于信号到达的异步性质而出现竞争条件或其他意外结果的可能性。
如果您想了解有关
pselect()
的更多信息,这里有一篇好文章就在这里。First, for what you're trying to-do, your signal handler is way too complex. Secondly, calling
signal()
inside your signal handler is not a good idea ... it's not an asynchronous signal-safe function.What you can do is the following:
signal()
like you've done.sigprocmask()
. This prevents a spurious signal from arriving before the call topselect()
.sig_atomic_t
pselect()
instead ofselect()
. This will allow you to change the process signal mask to allow a SIGINT signal to arrive, and it will do-so in an atomic manner with respect to signals. Otherwise, you could have your SIGINT arrive before the call toselect()
, and then you have "lost" that signal, even though it does set the flag in the handler.pselect()
call returns, detect whether the flag has been set.sig_atomic_t
flag was set, and you returned frompselect
because of a caught signal, then launch another function that will actually do all the ending of the child-processes and prompt the user, etc.Doing these steps will simplify your signal-handling code and reduce the chances of race-conditions or other unexpected results because of the asynchronous nature of signal arrival.
If you'd like some more information on
pselect()
, you there is a nice article on that here.