2017-07-31 39 views
-1

我在写一个多线程的linux C应用程序,执行线程需要每隔4小时执行一次(可以从几秒到几小时)。目前的实现基于usleep()。但是持续时间较长是非常不准确的。第一次睡眠需要4点20分,第二次5点等等。在linux中解决这个问题的正确方法是什么?可以使用linux定时器定期调度执行线程以获得更长的时间间隔吗?Linux mutithreaded C程序<-> usleep()每小时间隔的调度精度

+1

如果你得到20分钟的漂移,我会说这是'usleep()'参数的问题,而不是调度问题。你如何计算睡眠间隔? – myaut

+0

类似usleep(x * 60 * 60 * 1000 * 1000),其中x是小时 – t3rmin4tor

+0

'useconds_t'只保证值高达'1.000.000'。我认为'setitimer()'应该对这个目标更可靠。我会用一个小例子来详细说明我的答案。 –

回答

1

您可以在SIGALRM处理程序中将setitimer()self-pipe trick结合使用。应定期调度的线程必须在管道的读取端执行阻塞read()

看到这个玩具的使用示例展示了主意:

#define _POSIX_C_SOURCE 200101L 
#define _BSD_SOURCE 
#include <errno.h> 
#include <pthread.h> 
#include <signal.h> 
#include <stdio.h> 
#include <sys/time.h> 
#include <unistd.h> 

int pipefd[2]; 
const char pipechar = 'x'; 

void *periodicThread(void *arg) 
{ 
    (void)arg; // unused 

    char c; 
    while (read(pipefd[0], &c, 1) > 0) 
    { 
     if (c == 'q') break; 
     puts("scheduled!"); 
    } 
    return 0; 
} 

void alarmHandler(int signum) 
{ 
    (void)signum; // unused 

    write(pipefd[1], &pipechar, 1); 
} 

int main(void) 
{ 
    if (pipe(pipefd) < 0) return 1; 
    int rc = 1; 

    pthread_t thread; 
    if (pthread_create(&thread, 0, periodicThread, 0) != 0) 
     goto cleanup_pipe; 

    struct sigaction sa = { 
     .sa_handler = alarmHandler, 
     .sa_flags = SA_RESTART // aternatively check for EINTR after avery system call 
    }; 

    if (sigaction(SIGALRM, &sa, 0) < 0) goto cleanup_thread; 

    // use (much) larger values here! 
    struct itimerval itv = { 
     .it_interval = { 
      .tv_sec = 5, 
      .tv_usec = 0 
     }, 
     .it_value = { 
      .tv_sec = 5, 
      .tv_usec = 0 
     } 
    }; 

    if (setitimer(ITIMER_REAL, &itv, 0) < 0) goto cleanup_thread; 

    rc = 0; 
    int c; 
    while ((c = getchar()) != EOF) 
    { 
     if (c == 'q') break; 
    } 

    const char pipeendchar = 'q'; 
cleanup_thread: 
    write(pipefd[1], &pipeendchar, 1); 
    pthread_join(thread, 0); 

cleanup_pipe: 
    close(pipefd[0]); 
    close(pipefd[1]); 

    return rc; 
} 

如果你的月经变得很长,即使在struct itimervaltime_t领域,你可以选择一个更小的周期,只是计数SITGALRM数你接收。

+0

谢谢菲利克斯。我没有使用超过秒的定时器。 sleep()系列函数的情况也是如此。这是一个特殊的案例,每个人都在谈论有关cron的工作,当它变成小时或数天。 – t3rmin4tor

+0

@ t3rmin4tor另请参阅我的编辑。代码解释可能比一句话:) –

+0

这是非常有帮助的。欣赏它! – t3rmin4tor