如何让两个进程不断地互相发信号?
How to make two processes signalling each others continuously?
我想模拟一个游戏服务器,它应该用 parent 连续发送和接收信号。场景如下:
- Parent 向游戏发送信号。
- 游戏捕获信号并将信号发送到 parent。
- Parent 捕获信号并再次向游戏发送信号。
等等...
问题是在第一圈后停止接收或发送:
static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{
game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}
输出如下:
game
parent
为什么停在这里?游戏服务器不应该捕获parent的信号并再次打印"game"吗...
默认情况下,从进程收到此特定信号的那一刻起,直到相关的信号处理程序已离开,才会阻止接收特定信号。
来自 man 3 signal
:
void (*signal(int sig, void (*func)(int)))(int);
[...]
When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.
要更改此行为,请通过 sigaction()
而不是 signal()
建立信号处理(出于可移植性原因,应该采取任何方式)。
sigaction()
需要一个struct sigaction
。后者的成员sa_flags
应该设置SA_NODEFER
。
SA_NODEFER
Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.
SA_NODEFER
If set and sig is caught, sig shall not be added to the
thread's signal mask on entry to the signal handler
unless it is included in sa_mask. Otherwise, sig shall
always be added to the thread's signal mask on entry to
the signal handler.
请注意,每个信号处理程序在每次被调用时都会分配自己的堆栈,因此这种递归乒乓球迟早会出现内存不足的情况。
使用消息队列或共享内存来执行此操作。如上所述,这最终会 运行 内存不足并且会崩溃。
我想模拟一个游戏服务器,它应该用 parent 连续发送和接收信号。场景如下:
- Parent 向游戏发送信号。
- 游戏捕获信号并将信号发送到 parent。
- Parent 捕获信号并再次向游戏发送信号。
等等...
问题是在第一圈后停止接收或发送:
static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{
game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}
输出如下:
game
parent
为什么停在这里?游戏服务器不应该捕获parent的信号并再次打印"game"吗...
默认情况下,从进程收到此特定信号的那一刻起,直到相关的信号处理程序已离开,才会阻止接收特定信号。
来自 man 3 signal
:
void (*signal(int sig, void (*func)(int)))(int);
[...]
When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.
要更改此行为,请通过 sigaction()
而不是 signal()
建立信号处理(出于可移植性原因,应该采取任何方式)。
sigaction()
需要一个struct sigaction
。后者的成员sa_flags
应该设置SA_NODEFER
。
SA_NODEFER
Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.
SA_NODEFER
If set and sig is caught, sig shall not be added to the thread's signal mask on entry to the signal handler unless it is included in sa_mask. Otherwise, sig shall always be added to the thread's signal mask on entry to the signal handler.
请注意,每个信号处理程序在每次被调用时都会分配自己的堆栈,因此这种递归乒乓球迟早会出现内存不足的情况。
使用消息队列或共享内存来执行此操作。如上所述,这最终会 运行 内存不足并且会崩溃。