Im working on a assignment which uses signals to transfer a binary message between two processes, with the goal of learning about signals (it is a strange use indeed).
我正在做一个作业,使用信号在两个进程之间传输二进制信息,目的是学习信号(这确实是一个奇怪的用法)。
In my program, the two processes communicate a code, and then one transfers a message to the other. SIGUSR1 represents 0, SIGUSR2 represents 1. The idea is that the process sending the message will use the kill function with whichever SIGUSR to get the message across, and the receiving process will have a signal handler to interpret the codes.
在我的程序中,两个进程通信一个代码,然后一个进程将消息传递给另一个进程。SIGUSR1表示0,SIGUSR2表示1。其思想是,发送消息的进程将使用带有任何SIGUSR的kill函数来跨消息,接收进程将有一个信号处理程序来解释代码。
So here is the problem. I have the sender start up. it sleeps while it waits for the code to be sent. The reciever sends two SIGINT's to signify the 'password', using pidof(8)
to find the pid of the sender.
这就是问题所在。我让sender启动。它在等待发送代码时休眠。接收方通过pidof(8)来查找发送方的pid,发送方发送两个SIGINT表示“密码”。
Once the sender's signal handler has read these signals, recognizes it is the proper password, it then proceeds to send the message.
一旦发送方的信号处理程序读取了这些信号,确认它是正确的密码,它就会继续发送消息。
The reciever has now gone through a few functions, and is sleeping every second waiting for each bit to be passed via an interrupt. The problem is, this never happens.
接收者现在已经完成了一些功能,并且每一秒钟都在睡觉,等待每一个比特通过一个中断传递。问题是,这从来没有发生过。
I have set it up such that the sender is sending a bit(0 in this case) like so:
我已经设置好了,发送者发送了一点(在这种情况下是0):
kill(SIGUSR1,washingtonPID);
where washingtonPID is the PID of the receiver, and I have verified this is the correct PID.
在那里华盛顿PID是PID的接收器,我已证实这是正确的PID。
the receiver's handler is hooked up like so:
接收者的处理器是这样连接的:
//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;
}
where bit is a global variable. it is initially set to -1.
位是全局变量。它最初被设置为-1。
Here is the function which reads the bits:
这是读取位元的函数:
int receiveBit()
{
while(bit == -1)
{
sleep(1);
}
fprintf(stderr,"%d",bit);
int bit2 = bit;
bit = -1;
return bit2;
}
So the basic run through is this: After the code has been sent from the receiver to the sender, the sender starts to send kill signals of USR1 and USR2 to the receiver, which should eventually form a binary message.
所以最基本的运行是这样的:当代码从接收方发送到发送方之后,发送方开始向接收方发送USR1和USR2的杀伤信号,这将最终形成一个二进制消息。
The receiver is simply waiting at this point, sleeping every second. When it gets interrupted, the handler will set bit to 0 or 1, kicking it out of sleep, printing the bit, and returning it.
接收者只是在这里等待,每一秒钟都在睡觉。当它被中断时,处理程序将位设置为0或1,将其踢出休眠状态,打印该位并返回它。
If i let the two programs run normally, the reciever just sits in sleep, and the handler is never called (even though I can see the calls being made by the other process.
如果我让这两个程序正常运行,那么reciever就会处于休眠状态,并且永远不会调用处理程序(尽管我可以看到其他进程发出的调用)。
If i stop the sender, and manually send the Kill signals, i can send one, maybe two signals, both handled properly. any after that, and I get a message printed to the terminal like 'user signal 2'. Which is not something I have in my program, and the program immediately stops.
如果我停止发送者,并手动发送杀伤信号,我可以发送一个,也许两个信号,都处理得当。在那之后,我就会得到一条信息打印到终端,比如"用户信号2 "这在我的程序中是不存在的,程序会立即停止。
Any insights as to why my handler isn't being envoked, and why I can't manually send more then one or two signals would be greatly appreciated.
对于为什么我的处理器没有被注册,以及为什么我不能手工发送超过一两个信号的任何见解都将非常感谢。
Thanks for your time.
谢谢你的时间。
EDIT: It seems like people are stumped on this. Are there any debugging tips I could try?
编辑:人们似乎被这个问题难住了。有什么调试技巧我可以试试吗?
2 个解决方案
#1
5
As many have already commented, you shouldn't be doing this with signals at all. When it goes wrong (and it will, like it did) trying to find out what is wrong when undefined behaviour is behind it is hard if not impossible.
正如许多人已经评论过的,你根本不应该用信号来做这件事。当它出错的时候(它会,就像它所做的那样),试图找出不明确的行为背后的错误,如果不是不可能的话,也是很难的。
Using non async-safe system calls like fprintf inside signal handlers can corrupt the data since fprintf is operating on the same stream. Same with shared variables.
在信号处理程序中使用fprintf之类的非异步安全系统调用可能会破坏数据,因为fprintf正在同一流上操作。相同的共享变量。
Since you are using linux, signals of the same type will not be blocked, meaning that rapid delivery of the same signal can result in recursive call to the handler. Once a signal is caught, the disposition of the signal is reset to SIG_DFL and needs to be reestablished in the handler again (which can also fail if the signal is delived before it has the change to be reestablished).
由于您正在使用linux,所以不会阻塞相同类型的信号,这意味着快速传递相同的信号会导致对处理程序的递归调用。一旦一个信号被捕获,信号的处理将被重新设置为SIG_DFL,并且需要在处理程序中重新建立(如果信号在重新建立之前已经被删除,那么也会失败)。
That is why you can send a maximum of 1 signal of the same type before the signal gets reset to default and terminated the program with "user signal xx".
这就是为什么在信号被重置为默认并以“用户信号xx”终止程序之前,您可以发送最多1个相同类型的信号。
I would recommend you stop tormenting yourself with the code and grab some textbook or a tutorial and try to follow that.
我建议你不要再用代码折磨自己了,去找一些教科书或教程,然后试着照着做。
Signal call should also be avoided if it goes. From the man pages:
如果发生信号呼叫,也应该避免。从手册页:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.
signal()的行为在不同的UNIX版本中有所不同,在不同的Linux版本中也有不同的历史。避免使用:使用sigaction(2)代替。
#2
0
A couple things I notice.
我注意到一些事情。
- Any shared variables used in signal handlers should be set as
volatile
. - 在信号处理程序中使用的任何共享变量都应该设置为volatile。
- fprintf() is not a safe function to be used in a signal handler. Check your man page for
signal()
to get a list of the safe functions. - fprintf()不是在信号处理程序中使用的安全函数。检查您的手册页以获取一个安全功能列表。
- also, signal() has a couple different implementations for if a signal handler is reset back to SIG_DFL after being triggered. Most Unixes suggest to use
sigaction()
to make sure you get the behavior you want. Or to test you could reset the signal handler inside the handler itself, see if that gives you a different behavior. - 此外,signal()有两个不同的实现,用于在触发信号处理程序后将其重置为SIG_DFL。大多数Unixes都建议使用sigaction()来确保您得到您想要的行为。或者要测试,可以重置处理器内部的信号处理程序,看看它是否会给你一个不同的行为。
#1
5
As many have already commented, you shouldn't be doing this with signals at all. When it goes wrong (and it will, like it did) trying to find out what is wrong when undefined behaviour is behind it is hard if not impossible.
正如许多人已经评论过的,你根本不应该用信号来做这件事。当它出错的时候(它会,就像它所做的那样),试图找出不明确的行为背后的错误,如果不是不可能的话,也是很难的。
Using non async-safe system calls like fprintf inside signal handlers can corrupt the data since fprintf is operating on the same stream. Same with shared variables.
在信号处理程序中使用fprintf之类的非异步安全系统调用可能会破坏数据,因为fprintf正在同一流上操作。相同的共享变量。
Since you are using linux, signals of the same type will not be blocked, meaning that rapid delivery of the same signal can result in recursive call to the handler. Once a signal is caught, the disposition of the signal is reset to SIG_DFL and needs to be reestablished in the handler again (which can also fail if the signal is delived before it has the change to be reestablished).
由于您正在使用linux,所以不会阻塞相同类型的信号,这意味着快速传递相同的信号会导致对处理程序的递归调用。一旦一个信号被捕获,信号的处理将被重新设置为SIG_DFL,并且需要在处理程序中重新建立(如果信号在重新建立之前已经被删除,那么也会失败)。
That is why you can send a maximum of 1 signal of the same type before the signal gets reset to default and terminated the program with "user signal xx".
这就是为什么在信号被重置为默认并以“用户信号xx”终止程序之前,您可以发送最多1个相同类型的信号。
I would recommend you stop tormenting yourself with the code and grab some textbook or a tutorial and try to follow that.
我建议你不要再用代码折磨自己了,去找一些教科书或教程,然后试着照着做。
Signal call should also be avoided if it goes. From the man pages:
如果发生信号呼叫,也应该避免。从手册页:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.
signal()的行为在不同的UNIX版本中有所不同,在不同的Linux版本中也有不同的历史。避免使用:使用sigaction(2)代替。
#2
0
A couple things I notice.
我注意到一些事情。
- Any shared variables used in signal handlers should be set as
volatile
. - 在信号处理程序中使用的任何共享变量都应该设置为volatile。
- fprintf() is not a safe function to be used in a signal handler. Check your man page for
signal()
to get a list of the safe functions. - fprintf()不是在信号处理程序中使用的安全函数。检查您的手册页以获取一个安全功能列表。
- also, signal() has a couple different implementations for if a signal handler is reset back to SIG_DFL after being triggered. Most Unixes suggest to use
sigaction()
to make sure you get the behavior you want. Or to test you could reset the signal handler inside the handler itself, see if that gives you a different behavior. - 此外,signal()有两个不同的实现,用于在触发信号处理程序后将其重置为SIG_DFL。大多数Unixes都建议使用sigaction()来确保您得到您想要的行为。或者要测试,可以重置处理器内部的信号处理程序,看看它是否会给你一个不同的行为。