Aaron Yodaiken
Aaron Yodaiken

Reputation: 19551

how to avoid polling in pthreads

I've got some code that currently looks like this (simplified)

/* instance in global var *mystruct, count initialized to 0 */
typedef struct {
    volatile unsigned int count;
} mystruct_t;

pthread_mutex_t mymutex; // is initialized

/* one thread, goal: block while mystruct->count == 0 */
void x(void *n) {
    while(1) {
        pthread_mutex_lock(&mymutex);
        if(mystruct->count != 0) break;
        pthread_mutex_unlock(&mymutex);       
    }
    pthread_mutex_unlock(&mymutex);
    printf("count no longer equals zero");
    pthread_exit((void*) 0)
}

/* another thread */
void y(void *n) {
    sleep(10);
    pthread_mutex_lock(&mymutex);
    mystruct->count = 10;
    pthread_mutex_unlock(&mymutex);
}

This seems inefficient and wrong to me--but I don't know a better way of doing it. Is there a better way, and if so, what is it?

Upvotes: 4

Views: 2462

Answers (5)

caf
caf

Reputation: 239041

Condition variables are the solution to this problem. Your code can be fairly easily modified to use them:

pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;

/* one thread, goal: block while mystruct->count == 0 */
void x(void *n) {
    pthread_mutex_lock(&mymutex);
    while (mystruct->count == 0)
        pthread_cond_wait(&mycond, &mymutex);

    printf("count no longer equals zero");
    pthread_mutex_unlock(&mymutex);

    pthread_exit((void*) 0)
}

/* another thread */
void y(void *n) {
    sleep(10);
    pthread_mutex_lock(&mymutex);
    mystruct->count = 10;
    pthread_cond_signal(&mycond);
    pthread_mutex_unlock(&mymutex);
}

Note that you should generally keep the mutex locked while you act on the result - "consume" the event or similar. That's why I moved the pthread_mutex_unlock() to a point after the printf(), even though it doesn't really matter in this toy case.

(Also, in real code it might well make sense to put the mutex and condition variable inside mystruct).

Upvotes: 2

Clifford
Clifford

Reputation: 93476

A general solution is to use a POSIX semaphore. These are not part of the pthread library but work with pthreads just the same.

Since semaphores are provided in most other multi-threading APIs, it is a general technique that may be applied perhaps more portably; however perhaps more appropriate in this instance is a condition variable, which allows a thread to pend on the conditional value of a variable without polling, which seems to be exactly what you want.

Upvotes: 3

Manlio
Manlio

Reputation: 10865

You may also use semaphores to synchronize threads.

Upvotes: 0

user191776
user191776

Reputation:

You could use barriers.

Upvotes: 1

Maister
Maister

Reputation: 5054

Condition variables allow you to wait for a certain event, and have a different thread signal that condition variable.

You could have a thread that does this:

for (;;)
{
   if (avail() > 0)
      do_work();
   else
      pthread_cond_wait();
}

and a different thread that does this:

for (;;)
{
   put_work();
   pthread_cond_signal();
}

Very simplified of course. :) You'll need to look up how to use it properly, there are some difficulties working with condition variables due to race conditions.

However, if you are certain that the thread will block for a very short time (in order of µs) and rarely, using a spin loop like that is probably more efficient.

Upvotes: 4

Related Questions