1

I am developing a small application where in I want to call a function every 1 second. This is how I implemented

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);

But I want to run the TimerFn function in a separate pthread(basically a timer for pthread function). Can somebody please tell how to do this?

Harry
  • 2,177
  • 1
  • 19
  • 33
  • 2
    Have a look at [POSIX threads and signals](https://stackoverflow.com/questions/2575106/posix-threads-and-signals). As far as I can see, answer there is also a solution to your problem. – dhke Aug 29 '15 at 06:14
  • @dhke I have a doubt, if I create timer in a separate thread itself will the signal handler run inside that thread? – Harry Aug 29 '15 at 06:31
  • This has been subject to debate. It looks like Linux >= 2.6.12 have per-thread SIGALRM, while it was per-process (delivering to *any* thread) before that. POSIX seems to indicate it is per-process, basically meaning you simply cannot count on it. Whats wrong with [`timer_create()`](http://pubs.opengroup.org/onlinepubs/007908799/xsh/timer_create.html) and [`SIGEV_THREAD`](http://pubs.opengroup.org/onlinepubs/007908799/xsh/sigaction.html#tag_000_008_581_001)? – dhke Aug 29 '15 at 06:57
  • @dhke all I want is sgnal handler to be run in a separate thread upon generating the SIGALRM signal. So I want to know how to do it? – Harry Aug 29 '15 at 09:35

2 Answers2

2

If you can accept the creation of a new thread for every timer tick, you can use 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);

This will create a new thread for every tick.

If you need to handle the signal in a specific thread, a little more work is required:

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;
}

You might get away with selectively unblocking SIGARLM only in the signal handler thread, causing it the only thread to be eligible to handle that signal, but that may not be portable across systems.

Other versions (including use of pthread_cond_signal()) are already discussed in this answer.

dhke
  • 15,008
  • 2
  • 39
  • 56
0

If you just want to call a function every second, here's a simple solution:

#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);

Is there some reason this wouldn't suffice?

Steve Emmerson
  • 7,702
  • 5
  • 33
  • 59
  • but I would like to use timer_create to call the function every second instead of using sleep. Anyways thanks for the answer – Harry Aug 30 '15 at 03:39
  • This has slightly different realtime properties: It lengthens the period of a tick by whatever time `TimerFn()` needs to execute and those shifts accumulate across multiple ticks, which may or may not be okay for the scenario. – dhke Aug 31 '15 at 06:18
  • All portable timers are allowed to round-up. Also, this solution can be easily modified to match one-second time-centers by calling a higher-resolution timer and appropriately adjusting the sleep-time. The point is that this solution is less complicated and, therefore, easier to implement, understand, and maintain. Apparently, however, there's an unstated criterion that renders this solution unacceptable. – Steve Emmerson Aug 31 '15 at 15:11