C SIGALRM、间隔计时器和睡眠问题()
我正在将我们的一个嵌入式微控制器库移植到linux,并围绕它编写python包装器 我的一个低级模块依赖于每10毫秒调用一次的回调。此回调对每个软件计时器都有自己的回调进行计数。这些计时器在我们的图书馆里随处可见,虽然它们不一定要100%准确,但预计它们会继续滴答作响,并有望达到+/-10%的准确度。该模块模拟微控制器内的标准定时器中断 我有一个使用setitimer和SIGALRM处理程序的现有实现,它工作得非常好。以下是我的一些代码:C SIGALRM、间隔计时器和睡眠问题(),c,linux,signals,sleep,gevent,C,Linux,Signals,Sleep,Gevent,我正在将我们的一个嵌入式微控制器库移植到linux,并围绕它编写python包装器 我的一个低级模块依赖于每10毫秒调用一次的回调。此回调对每个软件计时器都有自己的回调进行计数。这些计时器在我们的图书馆里随处可见,虽然它们不一定要100%准确,但预计它们会继续滴答作响,并有望达到+/-10%的准确度。该模块模拟微控制器内的标准定时器中断 我有一个使用setitimer和SIGALRM处理程序的现有实现,它工作得非常好。以下是我的一些代码: void halCounterInit(void) {
void halCounterInit(void)
{
struct sigaction alrm_action;
alrm_action.sa_handler = timerInterrupt;
alrm_action.sa_flags = SA_RESTART;
sigaction(SIGALRM, &alrm_action, NULL);
}
void halCounterEnable(void)
{
mytime.it_interval.tv_sec = 0;
mytime.it_interval.tv_usec = 10000; //10ms
mytime.it_value.tv_sec = 0;
mytime.it_value.tv_usec = 10000; //10ms
setitimer(ITIMER_REAL, &mytime, NULL);
}
void halCounterDisable(void)
{
mytime.it_interval.tv_sec = 0;
mytime.it_interval.tv_usec = 0;
mytime.it_value.tv_sec = 0;
mytime.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &mytime, NULL);
}
void halCounterRegisterInterruptHandler(InterruptHandlerCallback cb, void *params)
{
myInterruptHandler = cb;
myParams = params;
}
void timerInterrupt(int signum)
{
if (myInterruptHandler != NULL)
{
myInterruptHandler(myParams);
}
}
在将其中一些代码与其他代码一起测试时,我注意到在生成SIGALRM信号时,对sleep()的调用会提前终止。我正在使用ctypes与python中的gevent(基于libevent)进行接口,以便在我的C库之上创建一个新层。我担心这个SIGALRM问题会导致难以在python中找到bug
我试图使用pthread和阻塞select()调用重写我的简单计数器,但是select()调用似乎很早就退出了,我的计时器变得非常不准确
while (TRUE)
{
pthread_mutex_lock(&Lock);
//we are paused
while(!Running)
{
//we are waiting for a signal to tell us when to start again
pthread_cond_wait(&Cond, &Lock);
}
pthread_mutex_unlock(&Lock);
RemTime.tv_nsec = 0;
do
{
nanosleep(&MyTime, &RemTime);
}
while(RemTime.tv_nsec != 0);
//select(0, NULL, NULL, NULL, &MyTime);
if (myInterruptHandler != NULL)
{
myInterruptHandler(myParams);
}
}
谢谢。每当出现非屏蔽信号时,它将中断任何正在运行的系统调用。有一个
SA_RESTART
选项(有关详细信息,请参阅man-s7 signal
),但该选项只会重新启动某些系统调用(例如,sleep
)。无论您使用什么信号,如果系统调用被中断,则根据上面的SA_RESTART
但书,行为将被改变。因此,您需要检查整个应用程序,确保正确处理返回代码EINTR
。当然,如果你使用睡眠
并且期望可靠性,那么这很难做到
我建议您最好不要使用信号,特别是如果您使用线程的话;这两个人打得不好。你说你希望它是便携式的:另一个避免像瘟疫这样的信号的原因
我要做的是设置另一个线程来执行计时器,并使用适当的互斥来保护计时器值。该线程可以使用
nanosleep
或pthread\u cond\u timedwait
(如果您希望某个条件打破它),一直休眠到下一步需要运行为止。在这两种情况下,您都需要包装调用以避免导致错误退出的信号。在调用之前读取时钟的当前值,将调用包装在do/while()
循环中,并测试时间是否确实超过了测试条件中所需的时间。传统上,人们使用gettimeofday
进行此操作,但这并不总是单调的,因此您可能希望clock\u gettime
具有clock\u单调的
,这取决于您对系统时间变化的反应。感谢您的支持。我确实尝试使用单独的线程以及select()和nanosleep,但无法获得正确的行为。我想我可以尝试对代码进行适当的包装,以解释传入并中断它的信号。我理解你关于EINTR的观点,但我担心的不一定是我的代码,而是我可能与之交互的各种python库。Re#1,是的,但正如@abligh在下面建议的那样,这是很难正确完成的(tm),尤其是库代码(不能对信号进行自由控制)。Re#2,是的,但我们无法帮助您调试看不到的代码。(顺便说一下,SIGALRM还是SIGVTALRM?你的叙述和你的代码说明了不同的事情。)@pilcrow,SIGALRM,我刚刚意识到我复制了一些我正在玩的调试代码。将编辑。