2011-02-05 90 views
6

我正在处理一个使用信号在两个进程之间传输二进制消息的任务,目的是了解信号(这确实是一个奇怪的用途)。为什么我的信号处理程序不被调用?

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

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

一旦发送者的信号处理程序已经读取这些信号,就认为它是正确的密码,然后继续发送消息。

接收器现在已经经历了几个函数,并且每秒钟都在睡觉,等待每个位通过中断传递。问题是,这从来没有发生过。

我已经设置它,使得发送者发送一个比特(0在这种情况下),如下所示:

kill(SIGUSR1,washingtonPID); 

其中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; 
} 

,其中一位是一个全局变量。它最初设置为-1。

这里是一个读取位功能:

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

所以基本运行经过是这样的: 代码已经从接收到发送方发送后,发送者开始发送的终止信号USR1和USR2到接收器,最终应该形成一个二进制消息。

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

,如果我让这两个程序运行正常,在reciever只是坐在睡眠和处理程序不会被调用(即使我可以看到调用由其他工艺制成。

如果我阻止发件人,然后手动发送Kill信号,我可以发送一个,也许两个信号,两者都可以正确处理,之后任何一个信息都会打印到终端上,如'用户信号2',这不是我的程序,程序立即停止

任何有关为什么我的处理程序没有被煽动的理解,以及为什么我不能手动发送更多的一个或两个信号,将不胜感激

感谢您的时间。

编辑: 看起来好像人们难住这一点。有没有我可以尝试的调试技巧?

+0

我可以告诉你的是,这是一个可笑的效率低下的设计,并且使用`pidof`来查找一个过程并不安全或不健全。 (想象一下,为了窃取密码,某个人使用相同的名称创建了一个进程。)您应该使用UNIX域套接字进行这种类型的通信。 – 2011-02-05 16:47:56

+3

如果您在第一段中会注意到,我提到这是一项任务而不是现实世界的问题。这是低效的,并且使用pidof是不安全的。但我并不担心这一点。 – Blackbinary 2011-02-05 16:54:14

+1

“bit”声明为“volatile”吗? – 2011-02-05 16:58:06

回答

5

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

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

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

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

我会建议你停止折磨自己的代码,并抓取一些教科书或教程,并尝试遵循。

信号调用也应该避免。从手册页:

信号的行为()跨 UNIX版本的不同而不同,也有所不同 历史跨越不同版本的Linux 。 避免使用:改为使用 sigaction(2)。

0

我注意到了几件事情。

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