【问题标题】:Using two pause() to catch two signals but failed使用两个 pause() 捕获两个信号但失败
【发布时间】:2013-12-23 13:15:48
【问题描述】:

我正在编写一个让两个孩子做某事的程序。当他们的工作完成时,这两个孩子会向其父母发送两个不同的信号。同时,父级使用两个pause() 等待其子级。

但是,程序在第一个pause() 之后停止,并在第二个pause() 处等待另一个信号。使用gdb,我发现收到了两个children的信号,但是只完成了一个pause()

这个问题的原因是什么?

主要:

struct sigaction parent_act;
struct sigaction child_act[2];

// set the signal handlers
parent_act.sa_handler = &p0_handler;
child_act[0].sa_handler = &p1_handler;
child_act[1].sa_handler = &p2_handler;

// set the behavior when child get signal SIGUSR1 and SIGUSR2 
sigaction(SIGUSR1, &child_act[0], NULL);
sigaction(SIGUSR2, &child_act[1], NULL);

// fork two child
for(i = 0; i < 2; i++){
    pid[i] = fork();
    // child process
    else if(pid[i] == 0){
        pause(); // wait for signal
        return 0;
    }
}

// set the behavior when parent get signal SIGUSR1 and SIGUSR2
sigaction(SIGUSR1, &parent_act, NULL);
sigaction(SIGUSR2, &parent_act, NULL);

kill(pid[0], SIGUSR1); // signal the child to do its job
kill(pid[1], SIGUSR2); // signal the other child to do its job
pause(); // wait for child
pause(); // wait for child

在处理程序中:

void p0_handler(int dummy)
{
    return;
}
void p1_handler(int dummy)
{
    // do something
    kill(getppid(), SIGUSR1); // tell parent it's done
    return;
}
void p2_handler(int dummy)
{
    // do something
    kill(getppid(), SIGUSR2); // tell parent it's done
    return;
}

第一个孩子发送 SIGUSR1 给父母,第二个孩子发送 SIGUSR2。似乎第一个pause() 收到了两个信号。这可能吗?

【问题讨论】:

  • 不同的信号”有什么不同?仅起源(child1 vs. child2)还是数字/类型/种类/...不同?
  • 你能添加一些代码吗?
  • 您是否设置了信号处理程序?
  • 如果两个信号到达同一个实例,pause 将无法处理它们。可能是两个子进程同时发送信号,而进程调度可能会玩一些讨厌的把戏。根据调用处理程序的时间,如果同时发送多个信号,您可能会在处理程序执行期间丢失信息。
  • 你是如何发送信号的?你使用的是哪个系统调用?

标签: c linux


【解决方案1】:

很可能两个信号同时到达(或第二个信号在信号处理程序执行期间到达),此时第二个pause 将无限期等待。

问题在于,即使您喜欢设置“一个孩子完成”标志,也无法保证在调用 pause 之前另一个信号不会到达。

使信号防水的唯一方法是在超时时使用select

int num_signals_received = 0;

void p0_handler(int dummy)
{
    // signal safe action
    __sync_fetch_and_add(&num_signals_received, 1);
    return;
}

而不是pause:

struct timeval timeout = {1,0}; // 1 second
while (num_signals_received < 2)
    select(0, NULL, NULL, NULL, &timeout);

如果您没有设置同步信号,那么我建议您转移到共享内存 (mmap/MAP_SHARED) 或基于文件描述符 (pipe(2)) 的同步。

【讨论】:

  • 如果我使用一个掩码来进一步阻止父信号处理程序的 SIGUSR1 和 SIGUSR2 怎么办?
  • @Stanley 您仍然不能保证在您最后一次操作和设置信号掩码之间没有信号到达。相信我:使用信号进行同步是个坏主意!
猜你喜欢
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
相关资源
最近更新 更多