2016-07-13 19 views
2

Ich möchte einen Timer starten und eine Funktion aufgerufen haben, wenn sie abläuft.Muss ich einen Signal-Handler für einen Posix-Timer verwenden?

Googling findet viele Beispiele, einschließlich des Beispiels im Handbuch, die alle sigaction() verwenden, um einen Signalhandler zu setzen.

Jedoch sagt @Patryk in this question, die wir

void cbf(union sigval); 
struct sigevent sev; 
timer_t timer; 

sev.sigev_notify = SIGEV_THREAD; 
sev.sigev_notify_function = cbf; //this function will be called when timer expires 
sev.sigev_value.sival_ptr = (void*) arg;//this argument will be passed to cbf 
timer_create(CLOCK_MONOTONIC, &sev, &timer); 

können, die kürzer, einfacher, sauberer, besser verwaltbar ...

Was soll das? Ist das richtig? Ist es nur ein Wrapper für sigaction()? Warum setzen die Beispiele explizit einen Signal-Handler?

Wenn ich einen Timer entweder durch diese Methode oder durch timer_settime und einen Signalhandler starte, wird das Abbrechen des Timers das System veranlassen, die Zuordnung zwischen diesem Timer und dem Rückruf zu entfernen, oder muss ich das explizit tun ?


[Update] Sie können wählen, entweder Signale der Methode, die ich in meiner Antwort unten zeigen (oder beides, aber das scheint dumm). Es ist Geschmackssache. Singals könnten ein bisschen mehr Funktionalität bieten, auf Kosten der Komplizentierung.

Wenn Sie nur einen Timer starten und benachrichtigt werden möchten, wenn er abläuft, ist die Methode in meiner Antwort am einfachsten.

+1

Ich denke, die Entscheidung, zwischen Threads oder Signalen als zugrundeliegende Benachrichtigungsschnittstelle für POSIX-Timer zu wählen, hängt vollständig von (auf Meinungen) ab, ob Sie bereit sind, Threads (aus welchen Gründen auch immer) für Ihre Anwendung zu verwenden Sie nicht, Sie sind gezwungen, das Thread-Benachrichtigungssystem aufgrund der Signalschnittstelle zu verwenden, die aus irgendeinem Grund keine Option ist (aus welchem ​​Grund auch immer ... ein guter Grund mag der Einfachheit halber sein). – pah

Antwort

0

Es scheint, dass ich einen Signal-Handler nicht verwenden müssen und können den Code wesentlich einfacher machen, wie hier gezeigt:

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <time.h> 
#include <unistd.h> 

static unsigned int pass_value_by_pointer = 42; 

void Timer_has_expired(union sigval timer_data) 
{ 
    printf("Timer expiration handler function; %d\n", *(int *) timer_data.sival_ptr); 
} 

int main(void) 
{ 
    struct sigevent timer_signal_event; 
    timer_t timer; 

    struct itimerspec timer_period; 

    printf("Create timer\n"); 
    timer_signal_event.sigev_notify = SIGEV_THREAD; 
    timer_signal_event.sigev_notify_function = Timer_has_expired;  // This function will be called when timer expires 
    // Note that the following is a union. Assign one or the other (preferably by pointer) 
    //timer_signal_event.sigev_value.sival_int = 38;      // This argument will be passed to the function 
    timer_signal_event.sigev_value.sival_ptr = (void *) &pass_value_by_pointer;  // as will this (both in a structure) 
    timer_signal_event.sigev_notify_attributes = NULL; 
    timer_create(CLOCK_MONOTONIC, &timer_signal_event, &timer); 

    printf("Start timer\n"); 
    timer_period.it_value.tv_sec = 1;         // 1 second timer 
    timer_period.it_value.tv_nsec = 0;         // no nano-seconds 
    timer_period.it_interval.tv_sec = 0;        // non-repeating timer 
    timer_period.it_interval.tv_nsec = 0; 

    timer_settime(timer, 0, &timer_period, NULL); 
    sleep(2); 

    printf("----------------------------\n"); 
    printf("Start timer a second time\n"); 
    timer_settime(timer, 0, &timer_period, NULL); 
    sleep(2); 

    printf("----------------------------\n"); 
    printf("Start timer a third time\n"); 
    timer_settime(timer, 0, &timer_period, NULL); 

    printf("Cancel timer\n"); 
    timer_delete(timer); 
    sleep(2); 
    printf("The timer expiration handler function should not have been called\n"); 

    return EXIT_SUCCESS; 
} 

bei der Ausführung, es diese Ausgabe gibt:

Create timer 
Start timer 
Timer expiration handler function; 42 
---------------------------- 
Start timer a second time 
Timer expiration handler function; 42 
---------------------------- 
Start timer a third time 
Cancel timer 
The timer expiration handler function should not have been called 
1

Linux hat timerfd. https://lwn.net/Articles/251413/. Dies ermöglicht eine sinnvolle Zeit zusammen mit select/poll/epoll zu verwenden. Alternativ können Sie das Timeout bei select/poll/epoll verwenden.

1

Michael Kerrisk hat ein ausführliches Beispiel in seinem "The Linux Programming Interface" Buch:

/* ptmr_sigev_thread.c 

    This program demonstrates the use of threads as the notification mechanism 
    for expirations of a POSIX timer. Each of the program's command-line 
    arguments specifies the initial value and interval for a POSIX timer. The 
    format of these arguments is defined by the function itimerspecFromStr(). 

    The program creates and arms one timer for each command-line argument. 
    The timer notification method is specified as SIGEV_THREAD, causing the 
    timer notifications to be delivered via a thread that invokes threadFunc() 
    as its start function. The threadFunc() function displays information 
    about the timer expiration, increments a global counter of timer expirations, 
    and signals a condition variable to indicate that the counter has changed. 
    In the main thread, a loop waits on the condition variable, and each time 
    the condition variable is signaled, the main thread prints the value of the 
    global variable that counts timer expirations. 

    Kernel support for Linux timers is provided since Linux 2.6. On older 
    systems, an incomplete user-space implementation of POSIX timers 
    was provided in glibc. 
*/ 
#include <signal.h> 
#include <time.h> 
#include <pthread.h> 
#include "curr_time.h"    /* Declares currTime() */ 
#include "tlpi_hdr.h" 
#include "itimerspec_from_str.h" /* Declares itimerspecFromStr() */ 

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

static int expireCnt = 0;   /* Number of expirations of all timers */ 
static void       /* Thread notification function */ 
threadFunc(union sigval sv) 
{ 
    timer_t *tidptr; 
    int s; 

    tidptr = sv.sival_ptr; 

    printf("[%s] Thread notify\n", currTime("%T")); 
    printf(" timer ID=%ld\n", (long) *tidptr); 
    printf(" timer_getoverrun()=%d\n", timer_getoverrun(*tidptr)); 

    /* Increment counter variable shared with main thread and signal 
     condition variable to notify main thread of the change. */ 

    s = pthread_mutex_lock(&mtx); 
    if (s != 0) 
     errExitEN(s, "pthread_mutex_lock"); 

    expireCnt += 1 + timer_getoverrun(*tidptr); 

    s = pthread_mutex_unlock(&mtx); 
    if (s != 0) 
     errExitEN(s, "pthread_mutex_unlock"); 

    s = pthread_cond_signal(&cond); 
    if (s != 0) 
     errExitEN(s, "pthread_cond_signal"); 
} 
int 
main(int argc, char *argv[]) 
{ 
    struct sigevent sev; 
    struct itimerspec ts; 
    timer_t *tidlist; 
    int s, j; 

    if (argc < 2) 
     usageErr("%s secs[/nsecs][:int-secs[/int-nsecs]]...\n", argv[0]); 

    tidlist = calloc(argc - 1, sizeof(timer_t)); 
    if (tidlist == NULL) 
     errExit("malloc"); 

    sev.sigev_notify = SIGEV_THREAD;   /* Notify via thread */ 
    sev.sigev_notify_function = threadFunc;  /* Thread start function */ 
    sev.sigev_notify_attributes = NULL; 
      /* Could be pointer to pthread_attr_t structure */ 

    /* Create and start one timer for each command-line argument */ 

    for (j = 0; j < argc - 1; j++) { 
     itimerspecFromStr(argv[j + 1], &ts); 

     sev.sigev_value.sival_ptr = &tidlist[j]; 
       /* Passed as argument to threadFunc() */ 

     if (timer_create(CLOCK_REALTIME, &sev, &tidlist[j]) == -1) 
      errExit("timer_create"); 
     printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]); 

     if (timer_settime(tidlist[j], 0, &ts, NULL) == -1) 
      errExit("timer_settime"); 
    } 

    /* The main thread waits on a condition variable that is signaled 
     on each invocation of the thread notification function. We 
     print a message so that the user can see that this occurred. */ 

    s = pthread_mutex_lock(&mtx); 
    if (s != 0) 
     errExitEN(s, "pthread_mutex_lock"); 

    for (;;) { 
     s = pthread_cond_wait(&cond, &mtx); 
     if (s != 0) 
      errExitEN(s, "pthread_cond_wait"); 
     printf("main(): expireCnt = %d\n", expireCnt); 
    } 
} 

von online source code genommen.

Lesen Sie auch das Kapitel 23 des Buches, dieser Code wird dort sehr ausführlich erklärt.

den obigen Code zu testen, ein

$ ./ptmr_sigev_thread 5:5 10:10 

Diese zwei Zeitgeber wird gesetzt eintreten würde: eine mit anfänglichen Ablauf von 5 Sekunden mit einem Intervall von 5 Sekunden und der andere mit 10 verbunden.

Die Definitionen für Hilfsfunktionen finden Sie, indem Sie dem Link im obigen Quellcode des Buches folgen.