Pepedou
Pepedou

Reputation: 829

Is it possible to have multiple timers in a multithreaded application in C Linux?

I'm writing a simple test to analyze the behavior of a multithreaded application when using POSIX timers.
I'm creating 3 threads, 3 timers, 3 events and 3 timerspecs.

What I'm trying to do is have each thread set a timer, wait for the timer to expire (which releases an unsafe lock) and finish the threads.
However, when I run the following program only the first timer expires which leads me to believe that perhaps it's not possible to have more than one timer per process. Is something wrong?

handle(union sigval params) is the callback for each timer when they expire.

threadTask(void *params) is the callback executed by each thread.

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <pthread.h>

typedef struct TH_PARAMS
{
    uint threadNum;
    pthread_t tid;
    timer_t *timer;
    struct sigevent *event;
} ThreadParams_t;

static timer_t timers[3];
static struct itimerspec timeToWait[3];
static struct sigevent events[3];
static ThreadParams_t thParams[3];
static char wait[3];

static void handle(union sigval params)
{
    ThreadParams_t *threadParams = (ThreadParams_t *) params.sival_ptr;
    printf("Timer %d expired. Thread num which sent %d. Thread %ld. Pthread %ld.\n",
       *((int*) *(threadParams->timer)), threadParams->threadNum,
       syscall(SYS_gettid), pthread_self());
    wait[threadParams->threadNum] = 0;
}

static void *threadTask(void *params)
{
    ThreadParams_t *threadParams = (ThreadParams_t *) params;

    printf("Thread num %d. Thread %ld. Pthread %ld.\n",
       threadParams->threadNum, syscall(SYS_gettid),
       pthread_self());

    if (0 != timer_settime(threadParams->timer, 0, &timeToWait[threadParams->threadNum], NULL))
    {
    printf("Failed to set timers. Error %d.\n", errno);
    pthread_exit(NULL);
    }

    while(wait) sleep(1);

    pthread_exit(NULL);
}

int main()
{
    int i;

    printf("Main thread started. Thread: %ld. Pthread: %ld\n", syscall(SYS_gettid), pthread_self());

    for (i = 0; i < 3; ++i)
    {
    timeToWait[i].it_value.tv_sec = 2;
    timeToWait[i].it_value.tv_nsec = 0;
    timeToWait[i].it_interval.tv_sec = 0;
    timeToWait[i].it_interval.tv_nsec = 0;

    events[i].sigev_notify = SIGEV_THREAD;
    events[i].sigev_notify_function = handle;
    events[i].sigev_value.sival_ptr = &thParams[i];

    if (0 != timer_create(CLOCK_MONOTONIC, &events[i], &timers[i]))
    {
        printf("Failed to create timers. Error %d.\n", errno);
        return 1;
    }

    wait[i] = 1;

    thParams[i].threadNum = i;
    thParams[i].event = &events[i];
    thParams[i].timer = &timers[i];

    if (0 != pthread_create(&thParams[i].tid, NULL, threadTask, (void *) &thParams[i]))
    {
        printf("Failed to create thread. Error %d.\n", errno);

        for (i = 0; i < 3; ++i)
        {
        if (timers[i])
        {
            timer_delete(timers[i]);
        }
        }

        return 1;
    }
    }

    for (i = 0; i < 3; ++i)
    {
    pthread_join(thParams[i].tid, NULL);
    }

    for (i = 0; i < 3; ++i)
    {
    if (timers[i])
    {
        timer_delete(timers[i]);
    }
    }

    printf("Main thread finished. Thread: %ld.\n", syscall(SYS_gettid));

    return 0;
}

Upvotes: 1

Views: 1812

Answers (1)

Pepedou
Pepedou

Reputation: 829

Okay, so I found my mistake. I was not dereferencing the timer pointer. In function threadTask, specifically in the timer_settime the first argument should be *threadParams->timer, emphasis on the *.

Upvotes: 2

Related Questions