首先要明白定时器类似中断性质,也就是说如果在一个单进程中开起一个定时器,一旦定时时间到,会直接转到定时器的处理函数中执行。
如果定时器是1s,而处理函数执行时长大于1S,会导致进程主任务无法执行。所以在使用定时器时处理函数的时长不能太长。
1, 定时器或者信号处理函数执行中允许睡眠吗?
可以睡眠,没有任何问题,但是最好保证下次信号来之前处理函数可以执行完,否则会导致进程主任务得不到执行时间。
2, 多线程中使用定时器时,如果在主线程设置定时器,信号处理函数可以与线程参与调度,也就是说如果信号处理函数被挂起后,线程会得到执行机会,但是主线程在信号处理函数挂起时无法得到执行机会。但要注意如果信号处理函数没有执行完,又来了信号,这时线程将得不到执行机会。
3, 信号处理函数中可以使用互斥锁吗?
最后不要使用,很容易造成死锁,有这样一种情况:线程中加锁,之后线程睡眠,这时信号来了,转而执行信号处理函数,这时处理函数由于获取不到锁又转入睡眠,这时就有问题了,如果线程很快醒来释放锁,信号处理函数获取到锁后可以继续运行,但是如果线程在下次信号到来依然没有释放锁,这样意味着又有一信号处理函数要等待执行,但是之前的处理函数还在等待锁释放,这把锁的持有者还是线程,这个线程由于第二次的信号导致无法再获取到执行时间所以死锁。
4, 在驱动设计中有这样一种设计方法:由于中断处理函数(上半部)执行时长要求尽可能短,所以耗时的工作交由一个线程执行——工作队列。这样一有中断就可以通知这个线程完成。那么linux应用层有这样类似的方法吗?
比如这样一个例子:
如果要求精确1S采集一次数据,但是采集数据的执行时间大概有900ms。
一种方法就会说使用定时器,在定时器的处理函数中完成数据采集,但是这样有可能会导致主进程的其他任务无法获取到执行时间。
类似这样的情况,我们可以采用类似内核中的方法。
这样来设计:
使用sigwait函数。
Sigwait函数可以等待被阻塞的信号,没有信号时阻塞线程,有信号时继续执行。
这样我们将定时器信号在所有线程(一定是所有线程,包括主线程,否则会执行信号处理函数)中阻塞,其中一个线程使用sigwait函数等待信号,这样1S一次的信号来了后,会导致这个线程运行完成900MS采集数据的工作,这样即使信号累计也没有关系,甚至线程还可以参与与主线程的调度,互斥锁也可以放心的使用。
当然之前考虑过条件量,这个也是可以实现的,但是条件量必须配和互斥量来使用,所以又必须在信号处理函数中使用互斥量了,这就要非常小心了。