为什么不调用我的信号处理程序?

时间:2011-02-05 16:42:55

标签: c unix posix signals

我正致力于一项使用信号在两个进程之间传输二进制消息的任务,目的是了解信号(这确实是一种奇怪的用法)。

在我的程序中,这两个进程传递一个代码,然后一个传递一个消息到另一个。 SIGUSR1代表0,SIGUSR2代表1.想法是发送消息的进程将使用kill函数和任何SIGUSR来获取消息,接收进程将有一个信号处理程序来解释代码。

所以这就是问题所在。 我有发件人启动。它在等待代码发送时休眠。 收件人发送两个SIGINT来表示“密码”,使用pidof(8)查找发件人的pid。

一旦发送者的信号处理程序读取了这些信号,识别出它是正确的密码,然后继续发送消息。

接收器现在经历了一些功能,并且每秒钟都在等待通过中断传递每个位。问题是,这种情况从未发生过。

我已将其设置为发送方正在发送一个位(在这种情况下为0),如下所示:

kill(washingtonPID,SIGUSR1);

其中washingtonPID是接收器的PID,我已经证实这是正确的PID。

接收者的处理程序如此连接:

//IN MAIN
    signal(SIGINT,bitReceiver);
    signal(SIGUSR1,bitReceiver);
    signal(SIGUSR2,bitReceiver);
//OUTSIDE MAIN

    void bitReceiver(int signum)
{
    if(signum == SIGUSR1)
    {
        fprintf(stderr,"SIGUSR1 - 0");
        bit = 0;
    }
    else if (signum == SIGUSR2)
    {
        fprintf(stderr,"SIGUSR2 - 1");
        bit = 1;
    }
    else //sigint
    raise(SIGINT);

    return;
}

其中bit是全局变量。它最初设置为-1。

这是读取位的函数:

 int receiveBit()
{
    while(bit == -1)
    {
        sleep(1);
    }
    fprintf(stderr,"%d",bit);
    int bit2 = bit;
    bit = -1;
    return bit2;
}

所以基本的运行是这样的: 代码从接收方发送到发送方后,发送方开始向接收方发送USR1和USR2的kill信号,最终形成二进制消息。

接收器只是在这一点等待,每秒钟都在睡觉。当它被中断时,处理程序将位设置为0或1,将其踢出睡眠状态,打印该位并返回它。

如果我让两个程序正常运行,接收器就处于休眠状态,并且永远不会调用处理程序(即使我可以看到其他进程正在进行调用。

如果我停止发送器,并手动发送Kill信号,我可以发送一个,也许两个信号,两者都处理得当。之后,我收到一条消息,如“用户信号2”,打印到终端。这不是我的程序中的东西,程序会立即停止。

有关为什么我的处理程序没有被调用的任何见解,以及为什么我不能手动发送超过一个或两个信号,我将不胜感激。

感谢您的时间。

编辑: 看起来人们对此感到难过。有没有我可以尝试的调试技巧?

2 个答案:

答案 0 :(得分:5)

许多人已经评论过,你根本不应该用信号做这件事。当它出错时(它会像它一样)试图找出未定义的行为背后的错误,即使不是不可能也很难。

在信号处理程序内部使用非异步安全系统调用(如fprintf)可能会破坏数据,因为fprintf在同一个流上运行。与共享变量相同。

由于您使用的是linux,因此不会阻止相同类型的信号,这意味着快速传递相同的信号可能会导致对处理程序的递归调用。捕获到信号后,信号的处置将重置为SIG_DFL,并且需要再次在处理程序中重新建立(如果在重新建立更改之前传送信号,也可能会失败)。

这就是为什么你可以在信号重置为默认值之前发送最多1个相同类型的信号,并用“用户信号xx”终止程序。

我建议你不要再使用代码折磨自己,拿一些教科书或教程,然后尝试遵循。

如果它发生,也应该避免信号呼叫。从手册页:

  

signal()的行为各不相同   UNIX版本,也有各种各样   历史上跨越不同的版本   Linux。 避免使用:使用   sigaction(2)而不是。

答案 1 :(得分:0)

我注意到了几件事。

  • 信号处理程序中使用的任何共享变量都应设置为volatile
  • fprintf()不是在信号处理程序中使用的安全函数。查看您的手册页signal()以获取安全功能列表。
  • 另外,如果信号处理程序在被触发后重置回SIG_DFL,则signal()有几个不同的实现。大多数Unix建议使用sigaction()来确保获得所需的行为。或者为了测试你可以重置处理程序本身内部的信号处理程序,看看是否会给你一个不同的行为。