当我在写一个使用定时器以固定的采样率(200Hz的)做一些数据采集和处理应用程序中处理“intterupted系统调用”的错误。 应用程序像服务器一样运行并在后台运行。它应该可以从其他进程或来自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()系统调用的主程序中有一个无限循环。
问题是,当收到'start'命令,然后定时器正常启动并运行(使用上面的代码)时,由于SIGUSR1,我得到'中断系统调用'错误(EINTR)定时器发送的信号中断了recvfrom()调用。如果我检查这个特定的错误代码并忽略它,当调用recvfrom()时,我终于得到'连接被拒绝'错误。
所以在这里我的问题:
- 如何解决这个“中断的系统调用”的错误,因为它似乎 忽略它,重新做recvfrom的()不工作?
- 为什么在大约20次尝试后出现“连接被拒绝”错误?
- 我有一种感觉,使用SIGEV_THREAD可能是一个解决方案,我的理解是,创建一个新的线程(如phread_create)不产生信号。我对吗?
- 信号号码在这里很重要吗?使用实时信号还有什么优点?
- 是否有任何其他的方式做什么,我打算做的:具有从UDP和实时周期任务后台循环检查命令?
而且这里的奖金问题:
- 它是安全的进行数据采集和处理的处理程序或我应该使用一个信号量机制来唤醒一个线程,这样做?
解决方案: 作为一个答案,并在评论中建议,使用SA_RESTART似乎解决的主要问题。
解决方案2: 通过SIGEV_SIGNAL使用SIGEV_THREAD也起作用。我读过使用SIGEV_THREAD可能需要比SIGEV_SIGNAL更多的资源的地方。但是,我没有看到有关任务时间的重大差异。
我并不完全了解你的情况,但是避免在信号处理程序中做“真正的工作”的一种优雅方法是打开一个管道到自身,让信号处理程序写入管道,并让main选择循环(我猜你有一个)从管道读取并做真正的工作。我不知道这是否能满足您的时间需求。至少管道避免了并发问题,因为从管道读取和写入是原子的(并且在它们之间存在上下文切换),这也避免了需要连续切换sigmask。 – wildplasser 2012-07-26 20:04:43
我不确定我是否理解了你的所有问题,但是你可以尝试将'SA_RESTART'添加到'sa_flags'吗? – ninjalj 2012-07-26 20:12:41
wildplasser>我没有任何选择循环,因为我只有一件事要做:检查通过带有'recvfrom' – pahpaul 2012-07-26 22:38:52