我希望在10的幂的频率上被中断,因此启用/ dev / rtc的中断并不理想。我想在中断之间睡1毫秒或250微秒。
启用/ dev / hpet的定期中断非常有效,但它似乎在某些机器上不起作用。显然我不能在没有HPET的机器上使用它。但我无法让它在一些可以作为时钟源使用的机器上工作。例如,在Core 2 Quad上,当设置为poll时,内核文档中包含的示例程序在HPET_IE_ON处失败。
使用Linux提供的itimer接口而不是直接与硬件设备驱动程序连接会更好。在某些系统上,itimer提供的定期中断随着时间的推移更加稳定。也就是说,由于hpet不能以我想要的频率中断,因此中断开始从挂起时间开始漂移。但我发现有些系统的睡眠时间比使用itimer要长(10+毫秒)。
这是一个使用itimer进行中断的测试程序。在某些系统上,它只打印出一个警告,它在目标时间内睡眠约100微秒左右。在其他情况下,它将打印出批次警告,它在目标时间内睡了10+毫秒。用-lrt编译并运行sudo chrt -f 50 [name]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#define NS_PER_SECOND 1000000000LL
#define TIMESPEC_TO_NS( aTime ) ( ( NS_PER_SECOND * ( ( long long int ) aTime.tv_sec ) ) \
+ aTime.tv_nsec )
int main()
{
// Block alarm signal, will be waited on explicitly
sigset_t lAlarm;
sigemptyset( &lAlarm );
sigaddset( &lAlarm, SIGALRM );
sigprocmask( SIG_BLOCK, &lAlarm, NULL );
// Set up periodic interrupt timer
struct itimerval lTimer;
int lReceivedSignal = 0;
lTimer.it_value.tv_sec = 0;
lTimer.it_value.tv_usec = 250;
lTimer.it_interval = lTimer.it_value;
// Start timer
if ( setitimer( ITIMER_REAL, &lTimer, NULL ) != 0 )
{
error( EXIT_FAILURE, errno, "Could not start interval timer" );
}
struct timespec lLastTime;
struct timespec lCurrentTime;
clock_gettime( CLOCK_REALTIME, &lLastTime );
while ( 1 )
{
//Periodic wait
if ( sigwait( &lAlarm, &lReceivedSignal ) != 0 )
{
error( EXIT_FAILURE, errno, "Failed to wait for next clock tick" );
}
clock_gettime( CLOCK_REALTIME, &lCurrentTime );
long long int lDifference =
( TIMESPEC_TO_NS( lCurrentTime ) - TIMESPEC_TO_NS( lLastTime ) );
if ( lDifference > 300000 )
{
fprintf( stderr, "Waited too long: %lld\n", lDifference );
}
lLastTime = lCurrentTime;
}
return 0;
}
答案 0 :(得分:7)
我遇到了与setitimer()设置相同的问题。 问题是默认情况下,您的进程由静态优先级0的SCHED_OTHER策略调度。这意味着您在一个包含所有其他进程的池中,并且动态优先级决定。有一些系统负载的那一刻,你会得到延迟。
解决方案是使用sched_setscheduler()系统调用,将静态优先级提高到至少一个,并指定SCHED_FIFO策略。它会带来巨大的改善。
#include <sched.h>
...
int main(int argc, char *argv[])
{
...
struct sched_param schedp;
schedp.sched_priority = 1;
sched_setscheduler(0, SCHED_FIFO, &schedp);
...
}
您必须以root身份运行才能执行此操作。另一种方法是使用chrt程序执行相同操作,但您必须知道RT过程的PID。
sudo chrt -f -p 1 <pid>
请参阅我的博客文章here。
答案 1 :(得分:5)
无论使用哪种正时机构的,当内核调度程序被调用(通常每秒100或1000倍),并与其他进程CPU争它归结为在任务的运行状态变化的组合。
我发现在Linux(Windows也是如此)上实现“最佳”时机的机制是执行以下操作:
这需要一些工作,但使用这种方法可以获得相当不错的结果。您可能需要查看相关问题here。