睡眠时信号处理比旋转时慢?
Signal handling slower when sleeping than spinning?
我试图理解为什么在主进程旋转时(while(1))比休眠时信号处理速度更快。
我使用以下代码创建了一个 500us 的一次性定时器
(基于 How to implement highly accurate timers in Linux Userspace?):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#define NSEC_PER_SEC 1000000000L
#define timerdiff(a,b) (((a)->tv_sec - (b)->tv_sec) * NSEC_PER_SEC + \
(((a)->tv_nsec - (b)->tv_nsec)))
struct timespec prev;
void handler( int signo )
{
struct timespec now;
unsigned long diff;
clock_gettime(CLOCK_MONOTONIC, &now);
diff = timerdiff(&now, &prev);
printf("%lu\n", diff);
exit(0);
}
int main(int argc, char *argv[])
{
int i = 0;
timer_t t_id;
struct itimerspec tim_spec = {.it_interval= {.tv_sec=0,.tv_nsec=0},
.it_value = {.tv_sec=0,.tv_nsec=500000}};
struct sigaction act;
sigset_t set;
sigemptyset( &set );
sigaddset( &set, SIGALRM );
act.sa_flags = 0;
act.sa_mask = set;
act.sa_handler = &handler;
sigaction( SIGALRM, &act, NULL );
if (timer_create(CLOCK_MONOTONIC, NULL, &t_id))
perror("timer_create");
clock_gettime(CLOCK_MONOTONIC, &prev);
if (timer_settime(t_id, 0, &tim_spec, NULL))
perror("timer_settime");
#ifdef SLEEP
while(1)
sleep(1);
#else
while(1);
#endif
return 0;
}
如果在定义 SLEEP 的情况下执行代码,执行 10 次会得到:
596940
549098
535758
606020
556990
528634
592051
545047
531079
541067
552520
如果 SLEEP 未定义,代码将旋转,我得到这些时间:
512641
510337
509778
510406
510057
507193
511245
511245
511384
509638
510127
真的好多了。
谁能给我解释一下?从睡眠中醒来比打断一个旋转的循环要慢?
它在 Intel 平台(8 核)上的 Linux 4.9 PREEMPT_RT 补丁内核上尝试了此代码,系统空闲。
谢谢!
奥雷利安
自旋时,内核不需要准备进程到运行,因为当信号到达时进程已经运行ning。它只需更改指令指针即可进入信号处理程序。
如果进程休眠,则必须将其放入任务队列,必须恢复上下文(寄存器、内存映射)和大量其他准备步骤,直到进程真正 运行s .
这有一点不同,但如果您查看总数,总共只有大约 10 - 100 微秒。
我试图理解为什么在主进程旋转时(while(1))比休眠时信号处理速度更快。
我使用以下代码创建了一个 500us 的一次性定时器 (基于 How to implement highly accurate timers in Linux Userspace?):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#define NSEC_PER_SEC 1000000000L
#define timerdiff(a,b) (((a)->tv_sec - (b)->tv_sec) * NSEC_PER_SEC + \
(((a)->tv_nsec - (b)->tv_nsec)))
struct timespec prev;
void handler( int signo )
{
struct timespec now;
unsigned long diff;
clock_gettime(CLOCK_MONOTONIC, &now);
diff = timerdiff(&now, &prev);
printf("%lu\n", diff);
exit(0);
}
int main(int argc, char *argv[])
{
int i = 0;
timer_t t_id;
struct itimerspec tim_spec = {.it_interval= {.tv_sec=0,.tv_nsec=0},
.it_value = {.tv_sec=0,.tv_nsec=500000}};
struct sigaction act;
sigset_t set;
sigemptyset( &set );
sigaddset( &set, SIGALRM );
act.sa_flags = 0;
act.sa_mask = set;
act.sa_handler = &handler;
sigaction( SIGALRM, &act, NULL );
if (timer_create(CLOCK_MONOTONIC, NULL, &t_id))
perror("timer_create");
clock_gettime(CLOCK_MONOTONIC, &prev);
if (timer_settime(t_id, 0, &tim_spec, NULL))
perror("timer_settime");
#ifdef SLEEP
while(1)
sleep(1);
#else
while(1);
#endif
return 0;
}
如果在定义 SLEEP 的情况下执行代码,执行 10 次会得到:
596940
549098
535758
606020
556990
528634
592051
545047
531079
541067
552520
如果 SLEEP 未定义,代码将旋转,我得到这些时间:
512641
510337
509778
510406
510057
507193
511245
511245
511384
509638
510127
真的好多了。
谁能给我解释一下?从睡眠中醒来比打断一个旋转的循环要慢?
它在 Intel 平台(8 核)上的 Linux 4.9 PREEMPT_RT 补丁内核上尝试了此代码,系统空闲。
谢谢!
奥雷利安
自旋时,内核不需要准备进程到运行,因为当信号到达时进程已经运行ning。它只需更改指令指针即可进入信号处理程序。
如果进程休眠,则必须将其放入任务队列,必须恢复上下文(寄存器、内存映射)和大量其他准备步骤,直到进程真正 运行s .
这有一点不同,但如果您查看总数,总共只有大约 10 - 100 微秒。