2015-08-29 124 views
0

我正在開發一個小應用程序,我想每1秒調用一個函數。這是我如何實現在使用timer_create的單獨pthread中的信號處理程序

Timerspec.it_interval.tv_sec=1; 
Timerspec.it_interval.tv_nsec=0; 
Timerspec.it_value.tv_sec=1; 
Timerspec.it_value.tv_nsec=0; 

timer_t timerId; 

struct sigaction sa; 
sa.sa_handler=&TimerFn; 
sa.sa_flags=0; 
sigemptyset(&sa.sa_mask); 
sigaction(SIGALRM,&sa,NULL); 

timer_create(CLOCK_REALTIME,NULL,&timerId); 
timer_settime(timerId,0,(const itimerspec*)Timerspec,NULL); 

但我想運行在一個獨立的並行線程的TimerFn功能(基本上是並行線程功能的定時器)。有人可以告訴如何做到這一點?

+0

對不起,有一個小錯字,我糾正了它。 – Harry

+1

看看[POSIX線程和信號](https://stackoverflow.com/questions/2575106/posix-threads-and-signals)。據我所見,回答也有解決您的問題的方法。 – dhke

+0

@dhke我有一個疑問,如果我在一個單獨的線程本身創建計時器將信號處理程序在該線程內運行? – Harry

回答

0

如果你能接受每一個計時器滴答一個新線程的創建,您可以使用SIGEV_THREAD

struct sigevent evp; 
memset((void *)&evp, 0, sizeof(evp)); 
evp.sigev_notify = SIGEV_THREAD; 
evp.sigev_notify_function = &sig_alrm_handler; 
evp.sigev_signo = SIGALRM; 
evp.sigev_value.sigval_ptr = (void *)this; 
int ret = timer_create(CLOCK_REALTIME, &evp, &_timerId); 

這將創建一個新的線程,每刻度。

如果您需要處理在一個特定的線程的信號,更多的工作是必需的:

static void * 
sig_threadproc(void *thrarg) 
{ 
    sigset_t sigset; 
    sigemptyset(&sigset); 
    sigaddset(&sigset, SIGALRM); 

    /* endless loop to wait for and handle a signal repeatedly */ 
    for (;;) { 
     int sig; 
     int error; 

     error = sigwait(&sigset, &sig); 
     if (error == 0) { 
      assert(sig == SIGALRM); 
      printf("got SIGALRM\n"); 
     } else { 
      perror("sigwait"); 
     } 
    } 
    return NULL; 
} 

static void 
sig_alrm_handler(int signo) 
{ 
    /** 
    * dummy signal handler, 
    * the signal is actually handled in sig_threadproc() 
    **/ 
} 


int 
main(int argc, char *argv[]) 
{ 
    sigset_t sigset; 
    struct sigaction sa; 
    pthread_t sig_thread; 
    struct itimerspec tspec; 
    timer_t timer_id; 

    /* mask SIGALRM in all threads by default */ 
    sigemptyset(&sigset); 
    sigaddset(&sigset, SIGALRM);   
    sigprocmask(SIG_BLOCK, &sigset, NULL); 

    /* we need a signal handler. 
    * The default is to call abort() and 
    * setting SIG_IGN might cause the signal 
    * to not be delivered at all. 
    **/ 
    memset(&sa, 0, sizeof(sa)); 
    sa.sa_handler = sig_alrm_handler; 
    sigaction(SIGALRM, &sa, NULL); 

    /* create SIGALRM looper thread */ 
    pthread_create(&sig_thread, NULL, sig_threadproc, NULL); 

    /* setup timer */ 
    tspec.it_interval.tv_sec = 1; 
    tspec.it_interval.tv_nsec = 0; 
    tspec.it_value.tv_sec = 1; 
    tspec.it_value.tv_nsec = 0; 

    timer_create(CLOCK_REALTIME, NULL, &timer_id); 
    timer_settime(timer_id, 0, &tspec, NULL); 

    /** 
    * this might return early if usleep() is interrupted (by a signal) 
    * It should not happen, since SIGALRM is blocked on the 
    * main thread 
    **/ 
    usleep(10000000); 

    return 0; 
} 

則可能是隻在信號處理器線程選擇性解鎖SIGARLM,導致它的唯一線索脫身有資格處理該信號,但這可能不是跨系統移植的。

其他版本(包括使用pthread_cond_signal())已在this answer中討論過。

+0

非常感謝。它真的幫了我很多 – Harry

0

如果你只是想調用一個函數每秒,這裏有一個簡單的解決方案:

#include <pthread.h> 
#include <unistd.h> 
void TimerFn(void) 
{ 
    ... 
} 
void* timer(void* arg) 
{ 
    for (;;) { 
    TimerFn(); 
    sleep(1); 
    } 
    return NULL; 
} 
... 
    pthread_t timerThread; 
    pthread_create(&timerThread, NULL, timer, NULL); 

是否有某種原因,這是不夠的?

+0

,但我想使用timer_create每秒調用一次函數,而不是使用sleep。無論如何感謝您的答案 – Harry

+0

這具有稍微不同的實時屬性:它隨着'TimerFn()'需要執行的時間延長了滴答的週期,並且這些移位在多個滴答中積累,這可能或可能不適用於該場景。 – dhke

+0

所有便攜式計時器都允許四捨五入。此外,通過調用更高分辨率的定時器並適當調整睡眠時間,此解決方案可以輕鬆修改爲匹配1秒時間中心。關鍵是這個解決方案不那麼複雜,因此更容易實現,理解和維護。然而,顯然,有一個不明確的標準使得這個解決方案不可接受。 –