【问题标题】:How to make two processes signalling each others continuously?如何让两个进程不断地相互发送信号?
【发布时间】:2016-05-28 09:36:00
【问题描述】:

我想模拟一个游戏服务器,它应该不断地与其父级发送和接收信号。场景如下:

  • 家长向游戏发送信号。
  • 游戏捕捉到信号并向父级发送信号。
  • 家长捕捉到信号并再次向游戏发送信号。

等等……

问题是第一圈后停止接收或发送:

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

为什么停在这里?游戏服务器不应该捕捉到父母的信号并再次打印“游戏”吗......

【问题讨论】:

  • 不是孩子在给孩子发信号,而父母不是在给自己发信号,也就是代码中的父母。在这种情况下,我通常会引入信号量和两种类型。 1个让父母等待,1个让孩子等待,2个while循环
  • 信号是实现 IPC 的主要错误选择。还有其他方式:SHM、管道、套接字、MQ
  • 孩子没有自己发信号,它发送 SIGUSR1 到 game_s 存储创建的孩子的 pid...不是吗?

标签: c linux process signals


【解决方案1】:

默认情况下,从进程接收到特定信号的那一刻起,直到相关的信号处理程序离开,特定信号的接收都会被阻止。

来自man 3 signal

void (*signal(int sig, void (*func)(int)))(int);

[...]

当一个信号出现时,func指向一个函数,实现定义是否等价于a:

         signal(sig, SIG_DFL);

执行或实现阻止某些实现定义的信号集(至少包括 sig)在当前信号处理完成之前发生。

要更改此行为,请通过 sigaction() 而不是 signal() 建立信号处理(出于可移植性原因,应该采取任何方式)。

sigaction() 采用struct sigaction。后者的成员sa_flags 应该设置SA_NODEFER

来自Linux' man 2 sigaction

SA_NODEFER

不要阻止从其自己的信号处理程序中接收信号。此标志仅在建立信号处理程序时才有意义。

POSIX words this differently:

SA_NODEFER

如果设置并且 sig 被捕获,则 sig 不应添加到 进入信号处理程序时线程的信号掩码 除非它包含在 sa_mask 中。否则,sig 应 总是在进入线程时添加到线程的信号掩码中 信号处理程序。


请注意,每个信号处理程序在每次调用时都会分配自己的堆栈,因此这种递归乒乓迟早会出现内存不足的情况。

【讨论】:

  • 谢谢你,解决了问题。我使用的是 sigaction,但我在示例中使用了 signal() 来实现简单性,但我错过了 SA_NODEFER 标志。现在可以使用了。
【解决方案2】:

使用消息队列或共享内存来执行此操作。如上所述,这最终会耗尽内存并崩溃。

【讨论】:

    猜你喜欢
    • 2019-12-28
    • 1970-01-01
    • 2011-10-12
    • 2017-06-07
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2012-04-22
    • 2017-12-04
    相关资源
    最近更新 更多