SIGINFO 的 si_pid 在多次调用同一函数后将自身设置为 0
SIGINFO's si_pid sets itself to 0 after a few calls of the same function
我正在做一个简单的项目,使 2 个进程使用信号相互通信。更具体地说,我正在使用带有标志 SA_SIGINFO 的 sigaction,这样每个进程都可以识别是谁向它发送了信号并进行回复。
事情是,在他们互相打电话几次之后(变化很大,有时发生在 3 次交换之后,其他时候发生在 700 次之后),siginfo returns a si_pid等于 0。
这是我用来使它们进行通信的两个代码。
首先,“服务器”
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_respond(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
i++;
printf("received - %d PID: %d\n", i, info->si_pid);
if (info ->si_pid != 0)
kill(info->si_pid, SIGUSR1);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(void)
{
struct sigaction reaction;
sigset_t mask;
reaction.sa_flags = SA_SIGINFO;
reaction.sa_sigaction = ft_respond;
sigaction(SIGUSR1, &reaction, NULL);
printf("PID = %d\n", getpid());
while (1)
pause();
return(0);
}
其次,“客户端”
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_send_signal(int pid)
{
kill(pid, SIGUSR1);
printf("sent\n");
}
void ft_signal_handler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
printf("recieved - %d PID: %d\n", i, info->si_pid);
i++;
if (info->si_pid != 0)
kill(info->si_pid, SIGUSR1);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(int ac, char **av)
{
struct sigaction action;
sigset_t set;
if (ac != 2)
exit (EXIT_FAILURE);
sigaddset(&set, SIGUSR1);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ft_signal_handler;
action.sa_mask = set;
sigaction(SIGUSR1, &action, NULL);
ft_send_signal(atoi(av[1]));
while(1)
pause();
return (0);
}
备注:
如果我删除行 if (info ->si_pid != 0)
,没有接收到信号的进程将永远暂停(呃!)而且有趣的是,另一个进程继续运行,就像它永远接收信号一样(不是啊!)。
我环顾四周以了解如何使用 sigfillset 或 sigaddset 来防止在我的处理程序仍在工作时出现任何传入信号,似乎没有什么可以破坏此行为。
我正在 运行MacBook 上运行这个程序,如果你想知道的话。
我也有 运行 Linux 上的程序(基于 Ubuntu 的发行版),我在那里没有发现“错误”。这对我来说很奇怪。
如果你想测试代码,这有点简单:用不同的名称编译每个程序(例如 gcc -o server server.c && gcc -o client client.c
), 运行 首先是服务器,然后是 运行 客户端,以服务器的 PID 作为参数。
在我因为对信号使用 printf 而受到抨击之前,我知道在 printf 执行期间信号中断的情况下不推荐这样做(参见 How to avoid using printf()
in a signal handler?), 但理论上,处理程序在发出信号时完成,因此它应该可以正常工作。我尝试使用 write 函数,它具有相同的行为。
如果您有任何线索,我可以跟随它使它正常工作,我将非常感激。
诊断
大多数时候,当我在 MacBook Pro 运行ning Big Sur 11.6.3 上进行测试时,命令 运行 完成。我正在使用程序 tester
到 运行 服务器,然后是客户端 — 该程序的优点是我可以准确地报告客户端和服务器程序的退出状态。我一直在使用越来越复杂的测试平台来捕获信息。
每隔一段时间,我似乎让服务器立即死机。我认为这是 时间问题 由于 o/s 调度程序。启动代码 运行 在启动服务器后发送给客户端,但碰巧系统调度程序 运行 在服务器设置其信号处理程序之前发送客户端,因此服务器被客户端的终止初始信号。
支持证据
我修改了客户端和服务器程序以包含 alarm(15);
以便进程在 15 秒后超时。大多数情况下,两人只需不到一秒钟的时间即可完成。在那些失败的情况下,我让服务器以状态 0x001E 退出(这表明它死于 SIGUSR1 信号)并且在相同的 运行s 上,客户端在 15 秒后以状态 0x000E 退出(这表明它死了来自 SIGALRM 信号)。日志文件不包含“received
”消息。
$ rmk && timecmd -m -- ./tester | tpipe -sx "grep -c -e '^C received'" "grep -c -e '^S received'" "grep -E -e 'PID =|^Child|(Server|Client) PID'" "cat > log.$(isodate -c)"
2022-02-15 14:25:07.172 [PID 10210] ./tester
tpipe: + grep -c -e '^C received'
tpipe: + grep -c -e '^S received'
tpipe: + grep -E -e 'PID =|^Child|(Server|Client) PID'
tpipe: + cat > log.20220215.142507
Server PID: 10211
Client PID: 10212
10212: sent signal to PID = 10211
Child 10211 exited with status 0x001E
Child 10212 exited with status 0x000E
2022-02-15 14:25:22.193 [PID 10210; status 0x0000] - 15.021s
0
0
$
10211 的状态消息几乎立即出现; 10212 等待了 15 秒多一点。两个零来自 grep -c
命令——没有有趣的消息。
相比之下,之前的 运行 显示:
$ rmk && timecmd -m -- ./tester | tpipe -sx "grep -c -e '^C received'" "grep -c -e '^S received'" "grep -E -e 'PID =|^Child|(Server|Client) PID'" "cat > log.$(isodate -c)"
2022-02-15 14:25:05.965 [PID 10196] ./tester
tpipe: + grep -c -e '^C received'
tpipe: + grep -c -e '^S received'
tpipe: + grep -E -e 'PID =|^Child|(Server|Client) PID'
tpipe: + cat > log.20220215.142505
Server PID: 10197
Client PID: 10198
PID = 10197
10198: sent signal to PID = 10197
Child 10197 exited with status 0x0000
Child 10198 exited with status 0x0000
2022-02-15 14:25:06.481 [PID 10196; status 0x0000] - 0.515s
5000
5000
$
此处的 5000 个条目是 grep -c
命令 运行 通过 tpipe
程序的计数。 (rmk
是 make
的变体;tpipe
是一个有点像 tee
的程序,除了它写入进程而不是文件(另请参见不幸命名为 pee
program); isodate
以压缩的 ISO 8601 格式打印日期,例如 20220215.142505
; timecmd -m
执行命令并将其计时到毫秒,报告命令和状态等。 )
我没有记录过 info->si_pid == 0
的情况,也没有记录过一些中间数量的信号交换后出现问题的情况 — 它是 0 或 5000,没有其他值。因此,我可能没有准确地重现您的场景。
使用 shell 脚本启动服务器,然后客户端没有重现过早的信号 — 处理 shell 脚本的固有延迟似乎足以让服务器在客户端发送初始信号之前设置其信号处理。
已测试脚本:
time=$(isodate -c)
server > server.$time.log &
client $! > client.$time.log
修改代码
JFTR,这是我修改后的代码。它使用了我的 SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c
and stderr.h
in the src/libsoq sub-directory.
中可用的一些代码
client.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "stderr.h"
static void ft_send_signal(int pid)
{
if (kill(pid, SIGUSR1) != 0)
err_syserr("failed to send initial signal to PID %d: ", pid);
printf("%d: sent signal to PID = %d\n", getpid(), pid);
fflush(stdout);
}
static void ft_signal_handler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
printf("C received - %d PID: %d\n", i, info->si_pid);
fflush(stdout);
i++;
if (info->si_pid != 0)
{
if (kill(info->si_pid, SIGUSR1) != 0)
err_syserr("failed to send signal to PID %d: ", info->si_pid);
}
else
err_error("info->si_pid == 0 at iteration %d\n", i);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(int ac, char **av)
{
err_setarg0("client");
struct sigaction action;
sigset_t set;
if (ac != 2)
err_usage("PID");
alarm(15);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ft_signal_handler;
action.sa_mask = set;
sigaction(SIGUSR1, &action, NULL);
ft_send_signal(atoi(av[1]));
while(1)
pause();
return (0);
}
server.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "stderr.h"
static void ft_respond(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
i++;
printf("S received - %d PID: %d\n", i, info->si_pid);
fflush(stdout);
if (info->si_pid != 0)
{
if (kill(info->si_pid, SIGUSR1) != 0)
err_syserr("failed to send signal to PID %d: ", info->si_pid);
}
else
err_error("info->si_pid == 0 at iteration %d\n", i);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(void)
{
err_setarg0("server");
struct sigaction reaction;
sigemptyset(&reaction.sa_mask);
alarm(15);
reaction.sa_flags = SA_SIGINFO;
reaction.sa_sigaction = ft_respond;
sigaction(SIGUSR1, &reaction, NULL);
printf("PID = %d\n", getpid());
fflush(stdout);
while (1)
pause();
return(0);
}
tester.c
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include "stderr.h"
int main(void)
{
err_setarg0("tester");
alarm(20);
pid_t server = fork();
if (server < 0)
err_syserr("failed to fork for server: ");
if (server == 0)
{
char *args[] = { "./server", 0 };
execv(args[0], args);
err_syserr("failed to exec server: ");
}
printf("Server PID: %d\n", server);
fflush(stdout);
pid_t client = fork();
if (client < 0)
err_syserr("failed to fork for client: ");
if (client == 0)
{
char buffer[20];
snprintf(buffer, sizeof(buffer), "%d", server);
char *argc[] = { "./client", buffer, 0 };
execv(argc[0], argc);
err_syserr("failed to exec client: ");
}
printf("Client PID: %d\n", client);
fflush(stdout);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
printf("Child %d exited with status 0x%.4X\n", corpse, status);
fflush(stdout);
}
return 0;
}
处方
我不确定是否有解决此问题的好方法,除了添加对客户端代码的调用以延迟它发送初始信号一段重要的时间——一两毫秒可能就足够了。这种延迟意味着服务器有时间设置其信号处理。同样,tester
程序可以在启动服务器和客户端之间增加延迟。
为什么 Linux 没有问题?运气?或者 o/s 调度程序不会在第一个 child 之前 运行 tester
的第二个 child,因此服务器总是在之前设置其信号处理客户端发送第一个信号。
所以,在尝试之后,我偶然发现了一个干净的解决方案。由于程序随机丢失 info->si_pid
,我将其值存储到 static int id
中并删除了条件 if (info->si_pid != 0)
。从现在开始,如果 info->si_pid == 0,我的 id 仍然存储着 pid。
这是它的样子。我将交易所推到了 50000,每次都非常有效。
服务器:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_respond(int sig, siginfo_t *info, void *context)
{
static int i = 0;
static int id = 0;
if (info->si_pid != 0)
id = info->si_pid;
(void)context;
if (sig == SIGUSR1)
{
i++;
printf("received - %d PID: %d\n", i, id);
kill(id, SIGUSR1);
if (i == 50000)
exit(EXIT_SUCCESS);
}
return ;
}
int main(void)
{
struct sigaction reaction;
reaction.sa_flags = SA_SIGINFO;
sigemptyset(&reaction.sa_mask);
reaction.sa_sigaction = ft_respond;
sigaction(SIGUSR1, &reaction, NULL);
printf("PID = %d\n", getpid());
while (1)
pause();
return(0);
}
客户:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_send_signal(int pid)
{
kill(pid, SIGUSR1);
printf("sent\n");
}
void ft_signal_handler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
static int id = 0;
if (info->si_pid != 0)
id = info->si_pid;
(void)context;
if (sig == SIGUSR1)
{
printf("recieved - %d PID: %d\n", i, id);
i++;
kill(id, SIGUSR1);
if (i == 50000)
exit(EXIT_SUCCESS);
}
return ;
}
int main(int ac, char **av)
{
struct sigaction action;
if (ac != 2)
exit (EXIT_FAILURE);
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ft_signal_handler;
sigaction(SIGUSR1, &action, NULL);
ft_send_signal(atoi(av[1]));
usleep(100);
while(1)
pause();
return (0);
}
现在看来,无论如何,进程都会继续相互发送信号。
我正在做一个简单的项目,使 2 个进程使用信号相互通信。更具体地说,我正在使用带有标志 SA_SIGINFO 的 sigaction,这样每个进程都可以识别是谁向它发送了信号并进行回复。 事情是,在他们互相打电话几次之后(变化很大,有时发生在 3 次交换之后,其他时候发生在 700 次之后),siginfo returns a si_pid等于 0。 这是我用来使它们进行通信的两个代码。 首先,“服务器”
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_respond(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
i++;
printf("received - %d PID: %d\n", i, info->si_pid);
if (info ->si_pid != 0)
kill(info->si_pid, SIGUSR1);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(void)
{
struct sigaction reaction;
sigset_t mask;
reaction.sa_flags = SA_SIGINFO;
reaction.sa_sigaction = ft_respond;
sigaction(SIGUSR1, &reaction, NULL);
printf("PID = %d\n", getpid());
while (1)
pause();
return(0);
}
其次,“客户端”
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_send_signal(int pid)
{
kill(pid, SIGUSR1);
printf("sent\n");
}
void ft_signal_handler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
printf("recieved - %d PID: %d\n", i, info->si_pid);
i++;
if (info->si_pid != 0)
kill(info->si_pid, SIGUSR1);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(int ac, char **av)
{
struct sigaction action;
sigset_t set;
if (ac != 2)
exit (EXIT_FAILURE);
sigaddset(&set, SIGUSR1);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ft_signal_handler;
action.sa_mask = set;
sigaction(SIGUSR1, &action, NULL);
ft_send_signal(atoi(av[1]));
while(1)
pause();
return (0);
}
备注:
如果我删除行
if (info ->si_pid != 0)
,没有接收到信号的进程将永远暂停(呃!)而且有趣的是,另一个进程继续运行,就像它永远接收信号一样(不是啊!)。我环顾四周以了解如何使用 sigfillset 或 sigaddset 来防止在我的处理程序仍在工作时出现任何传入信号,似乎没有什么可以破坏此行为。
我正在 运行MacBook 上运行这个程序,如果你想知道的话。
我也有 运行 Linux 上的程序(基于 Ubuntu 的发行版),我在那里没有发现“错误”。这对我来说很奇怪。
如果你想测试代码,这有点简单:用不同的名称编译每个程序(例如
gcc -o server server.c && gcc -o client client.c
), 运行 首先是服务器,然后是 运行 客户端,以服务器的 PID 作为参数。在我因为对信号使用 printf 而受到抨击之前,我知道在 printf 执行期间信号中断的情况下不推荐这样做(参见 How to avoid using
printf()
in a signal handler?), 但理论上,处理程序在发出信号时完成,因此它应该可以正常工作。我尝试使用 write 函数,它具有相同的行为。
如果您有任何线索,我可以跟随它使它正常工作,我将非常感激。
诊断
大多数时候,当我在 MacBook Pro 运行ning Big Sur 11.6.3 上进行测试时,命令 运行 完成。我正在使用程序 tester
到 运行 服务器,然后是客户端 — 该程序的优点是我可以准确地报告客户端和服务器程序的退出状态。我一直在使用越来越复杂的测试平台来捕获信息。
每隔一段时间,我似乎让服务器立即死机。我认为这是 时间问题 由于 o/s 调度程序。启动代码 运行 在启动服务器后发送给客户端,但碰巧系统调度程序 运行 在服务器设置其信号处理程序之前发送客户端,因此服务器被客户端的终止初始信号。
支持证据
我修改了客户端和服务器程序以包含 alarm(15);
以便进程在 15 秒后超时。大多数情况下,两人只需不到一秒钟的时间即可完成。在那些失败的情况下,我让服务器以状态 0x001E 退出(这表明它死于 SIGUSR1 信号)并且在相同的 运行s 上,客户端在 15 秒后以状态 0x000E 退出(这表明它死了来自 SIGALRM 信号)。日志文件不包含“received
”消息。
$ rmk && timecmd -m -- ./tester | tpipe -sx "grep -c -e '^C received'" "grep -c -e '^S received'" "grep -E -e 'PID =|^Child|(Server|Client) PID'" "cat > log.$(isodate -c)"
2022-02-15 14:25:07.172 [PID 10210] ./tester
tpipe: + grep -c -e '^C received'
tpipe: + grep -c -e '^S received'
tpipe: + grep -E -e 'PID =|^Child|(Server|Client) PID'
tpipe: + cat > log.20220215.142507
Server PID: 10211
Client PID: 10212
10212: sent signal to PID = 10211
Child 10211 exited with status 0x001E
Child 10212 exited with status 0x000E
2022-02-15 14:25:22.193 [PID 10210; status 0x0000] - 15.021s
0
0
$
10211 的状态消息几乎立即出现; 10212 等待了 15 秒多一点。两个零来自 grep -c
命令——没有有趣的消息。
相比之下,之前的 运行 显示:
$ rmk && timecmd -m -- ./tester | tpipe -sx "grep -c -e '^C received'" "grep -c -e '^S received'" "grep -E -e 'PID =|^Child|(Server|Client) PID'" "cat > log.$(isodate -c)"
2022-02-15 14:25:05.965 [PID 10196] ./tester
tpipe: + grep -c -e '^C received'
tpipe: + grep -c -e '^S received'
tpipe: + grep -E -e 'PID =|^Child|(Server|Client) PID'
tpipe: + cat > log.20220215.142505
Server PID: 10197
Client PID: 10198
PID = 10197
10198: sent signal to PID = 10197
Child 10197 exited with status 0x0000
Child 10198 exited with status 0x0000
2022-02-15 14:25:06.481 [PID 10196; status 0x0000] - 0.515s
5000
5000
$
此处的 5000 个条目是 grep -c
命令 运行 通过 tpipe
程序的计数。 (rmk
是 make
的变体;tpipe
是一个有点像 tee
的程序,除了它写入进程而不是文件(另请参见不幸命名为 pee
program); isodate
以压缩的 ISO 8601 格式打印日期,例如 20220215.142505
; timecmd -m
执行命令并将其计时到毫秒,报告命令和状态等。 )
我没有记录过 info->si_pid == 0
的情况,也没有记录过一些中间数量的信号交换后出现问题的情况 — 它是 0 或 5000,没有其他值。因此,我可能没有准确地重现您的场景。
使用 shell 脚本启动服务器,然后客户端没有重现过早的信号 — 处理 shell 脚本的固有延迟似乎足以让服务器在客户端发送初始信号之前设置其信号处理。
已测试脚本:
time=$(isodate -c)
server > server.$time.log &
client $! > client.$time.log
修改代码
JFTR,这是我修改后的代码。它使用了我的 SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c
and stderr.h
in the src/libsoq sub-directory.
client.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "stderr.h"
static void ft_send_signal(int pid)
{
if (kill(pid, SIGUSR1) != 0)
err_syserr("failed to send initial signal to PID %d: ", pid);
printf("%d: sent signal to PID = %d\n", getpid(), pid);
fflush(stdout);
}
static void ft_signal_handler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
printf("C received - %d PID: %d\n", i, info->si_pid);
fflush(stdout);
i++;
if (info->si_pid != 0)
{
if (kill(info->si_pid, SIGUSR1) != 0)
err_syserr("failed to send signal to PID %d: ", info->si_pid);
}
else
err_error("info->si_pid == 0 at iteration %d\n", i);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(int ac, char **av)
{
err_setarg0("client");
struct sigaction action;
sigset_t set;
if (ac != 2)
err_usage("PID");
alarm(15);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ft_signal_handler;
action.sa_mask = set;
sigaction(SIGUSR1, &action, NULL);
ft_send_signal(atoi(av[1]));
while(1)
pause();
return (0);
}
server.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "stderr.h"
static void ft_respond(int sig, siginfo_t *info, void *context)
{
static int i = 0;
(void)context;
if (sig == SIGUSR1)
{
i++;
printf("S received - %d PID: %d\n", i, info->si_pid);
fflush(stdout);
if (info->si_pid != 0)
{
if (kill(info->si_pid, SIGUSR1) != 0)
err_syserr("failed to send signal to PID %d: ", info->si_pid);
}
else
err_error("info->si_pid == 0 at iteration %d\n", i);
if (i == 5000)
exit(EXIT_SUCCESS);
}
}
int main(void)
{
err_setarg0("server");
struct sigaction reaction;
sigemptyset(&reaction.sa_mask);
alarm(15);
reaction.sa_flags = SA_SIGINFO;
reaction.sa_sigaction = ft_respond;
sigaction(SIGUSR1, &reaction, NULL);
printf("PID = %d\n", getpid());
fflush(stdout);
while (1)
pause();
return(0);
}
tester.c
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include "stderr.h"
int main(void)
{
err_setarg0("tester");
alarm(20);
pid_t server = fork();
if (server < 0)
err_syserr("failed to fork for server: ");
if (server == 0)
{
char *args[] = { "./server", 0 };
execv(args[0], args);
err_syserr("failed to exec server: ");
}
printf("Server PID: %d\n", server);
fflush(stdout);
pid_t client = fork();
if (client < 0)
err_syserr("failed to fork for client: ");
if (client == 0)
{
char buffer[20];
snprintf(buffer, sizeof(buffer), "%d", server);
char *argc[] = { "./client", buffer, 0 };
execv(argc[0], argc);
err_syserr("failed to exec client: ");
}
printf("Client PID: %d\n", client);
fflush(stdout);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
printf("Child %d exited with status 0x%.4X\n", corpse, status);
fflush(stdout);
}
return 0;
}
处方
我不确定是否有解决此问题的好方法,除了添加对客户端代码的调用以延迟它发送初始信号一段重要的时间——一两毫秒可能就足够了。这种延迟意味着服务器有时间设置其信号处理。同样,tester
程序可以在启动服务器和客户端之间增加延迟。
为什么 Linux 没有问题?运气?或者 o/s 调度程序不会在第一个 child 之前 运行 tester
的第二个 child,因此服务器总是在之前设置其信号处理客户端发送第一个信号。
所以,在尝试之后,我偶然发现了一个干净的解决方案。由于程序随机丢失 info->si_pid
,我将其值存储到 static int id
中并删除了条件 if (info->si_pid != 0)
。从现在开始,如果 info->si_pid == 0,我的 id 仍然存储着 pid。
这是它的样子。我将交易所推到了 50000,每次都非常有效。
服务器:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_respond(int sig, siginfo_t *info, void *context)
{
static int i = 0;
static int id = 0;
if (info->si_pid != 0)
id = info->si_pid;
(void)context;
if (sig == SIGUSR1)
{
i++;
printf("received - %d PID: %d\n", i, id);
kill(id, SIGUSR1);
if (i == 50000)
exit(EXIT_SUCCESS);
}
return ;
}
int main(void)
{
struct sigaction reaction;
reaction.sa_flags = SA_SIGINFO;
sigemptyset(&reaction.sa_mask);
reaction.sa_sigaction = ft_respond;
sigaction(SIGUSR1, &reaction, NULL);
printf("PID = %d\n", getpid());
while (1)
pause();
return(0);
}
客户:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void ft_send_signal(int pid)
{
kill(pid, SIGUSR1);
printf("sent\n");
}
void ft_signal_handler(int sig, siginfo_t *info, void *context)
{
static int i = 0;
static int id = 0;
if (info->si_pid != 0)
id = info->si_pid;
(void)context;
if (sig == SIGUSR1)
{
printf("recieved - %d PID: %d\n", i, id);
i++;
kill(id, SIGUSR1);
if (i == 50000)
exit(EXIT_SUCCESS);
}
return ;
}
int main(int ac, char **av)
{
struct sigaction action;
if (ac != 2)
exit (EXIT_FAILURE);
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ft_signal_handler;
sigaction(SIGUSR1, &action, NULL);
ft_send_signal(atoi(av[1]));
usleep(100);
while(1)
pause();
return (0);
}
现在看来,无论如何,进程都会继续相互发送信号。