我正在编写一个应用程序,它使用计时器以固定采样率(200Hz)进行一些数据采集和处理。该应用程序就像一个服务器并在后台运行。它应该可以从其他进程或来自 UDP 的其他机器控制。
为此,我使用 timer_create() API 定期生成 SIGUSR1 并调用执行获取和处理的处理程序。
配置定时器的代码如下(为了清楚起见减去错误检查):
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_ptr = &timerid;
timer_create(CLOCK_REALTIME, &sev, &timerid);
timer_settime(...)
当从 UDP 接收到“开始”命令时,将调用上面的代码。为了检查命令,我在调用 recvfrom() 系统调用的主程序中有一个无限循环。
问题是,当收到“开始”命令,然后定时器正确启动并运行(使用上面的代码)时,由于定时器发送的 SIGUSR1 信号,我得到一个“系统调用中断”错误(EINTR)中断 recvfrom() 调用。如果我检查这个特定的错误代码并忽略它,我最终会在调用 recvfrom() 时收到“连接被拒绝”错误。
所以这里是我的问题:
- 如何解决这个“中断的系统调用”错误,因为它似乎忽略它并重新执行 recvfrom() 不起作用?
- 为什么我在尝试大约 20 次后收到“连接被拒绝”错误?
- 我觉得使用 SIGEV_THREAD 可能是一种解决方案,据我了解,创建一个新线程(如 phread_create)而不生成信号。我对吗?
- 信号编号在这里重要吗?使用实时信号有什么好处吗?
- 有没有其他方法可以做我想做的事情:让后台循环检查来自 UDP 的命令和实时定期任务?
这里是奖金问题:
- 在处理程序中进行数据采集和处理是否安全,或者我应该使用信号量机制来唤醒执行此操作的线程?
解决方案: 正如答案和评论中所建议的那样,使用 SA_RESTART 似乎可以解决主要问题。
解决方案 2: 在 SIGEV_SIGNAL 上使用 SIGEV_THREAD 也可以。我在某处读到使用 SIGEV_THREAD 可能需要比 SIGEV_SIGNAL 更多的资源。但是,我没有看到关于任务时间的显着差异。