0

I have created multiple threads and want to run them in a round robin fashion using condition variable and signal ( pthread_cond_wait & pthread_cond_signal).

I have used two approach , one approach is working but wasting CPU whereas other approach not working, not wasting CPU.

The problem I am facing is signal is sent before my threads waiting and the signal is lost. so it goes into infinite waiting loop.

First approach :

Threads are created and waiting for condition variable and continuously checking for a varible called as state( inside a while loop).

when state == my_id the thread with my_id got activated and it then signal to next thread my_id+1 and so on.

DRAWBACK : Wastage of CPU

Second approach :

Threads are created and waiting for signal for its own condition variable. Now as signal was already sent before thread start waiting , signal is lost and program goes into infinite wait loop.

Is there anything like "Self Signalling " or other way to send signal when signal is lost ?

I am using g++ under linux. Any clue will be highly appreciated. Thanks in advance.

Program with first approach is here round robin .

Here is my program with second approach:

#include <pthread.h>
#include <stdio.h>
#include <iostream>
#include <mutex>          // std::mutex


#define MULTIPLE_THREADS 2
#define NTHREADS MULTIPLE_THREADS*64
#define NO_OF_LOOP 1


pthread_cond_t      cond[NTHREADS];
pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;


using namespace std;



/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
{ 
    long my_id = (long)arg;
    int i = 0;

    while(i < NO_OF_LOOP)
    {


        // Awaken or unblocked by thread (i-1) 
        pthread_mutex_lock(&mutex1);
        pthread_cond_wait(&cond[my_id], &mutex1);
        pthread_mutex_unlock(&mutex1);

        printf("I am thread - %ld",my_id);
        ++i;


         /* wake up thread i+1 */
        pthread_mutex_lock(&mutex1);
        pthread_cond_signal(&cond[(my_id + 1) % NTHREADS]);
        pthread_mutex_unlock(&mutex1);      
    }

    return NULL;
}

int main(void)
{

    pthread_t             threadid[NTHREADS];


    // Initialization   
    for(int i=0;i<NTHREADS;i++)
    cond[i]= PTHREAD_COND_INITIALIZER;

    //printf("Create %d threads\n", NTHREADS);
    for(long i=0; i<NTHREADS; ++i) {
    pthread_create(&threadid[i], NULL, threadA, (void *)i);
    //printf("Thread created=%d\n", i);
    }

    //  printf("Wait for threads and cleanup\n");
    for (long i=0; i<NTHREADS; ++i) {
    pthread_join(threadid[i], NULL);
    }

    return 0;
}
Community
  • 1
  • 1
bholanath
  • 1,699
  • 1
  • 22
  • 40

1 Answers1

3

You cannot use a condition variable in this manner. You always need a predicate. That is, you need a variable that you can test for whether an event has occurred.

Simply issuing a blind pthread_cond_wait and pthread_cond_signal will make you lose events. There could be spurious wakeups, and if the thread you signal is not blocked in pthread_cond_wait(), it will miss the event (pthread_cond_signal() does not queue up).

You will need something like this (not tested):

pthread_cond_t      cond[NTHREADS];
int                 wakeup[NTHREADS];
pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;


using namespace std;



/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
{ 
    long my_id = (long)arg;
    int i = 0;

    while(i < NO_OF_LOOP)
    {


        // Awaken or unblocked by thread (i-1) 
        pthread_mutex_lock(&mutex1);
        while (!wakeup[my_id]) {
            pthread_cond_wait(&cond[my_id], &mutex1);
        }
        wakeup[my_id] = 0;
        pthread_mutex_unlock(&mutex1);

        printf("I am thread - %ld",my_id);
        ++i;

        pthread_mutex_lock(&mutex1);
        //tell thread i to wake up
        wakeup[(my_id + 1) % NTHREADS] = 1; 
        pthread_cond_signal(&cond[(my_id + 1) % NTHREADS]);
        pthread_mutex_unlock(&mutex1);      
    }

    return NULL;
}
int main(void)
{

    pthread_t             threadid[NTHREADS];
    wakeup[0] = 1; //let thread 0 start.

EDIT. There's another error with the #define NTHREADS MULTIPLE_THREADS*64 macro too. The expression (my_id + 1) % NTHREADS will be not be evaluated correctly, the macro must be

 #define NTHREADS (MULTIPLE_THREADS*64)

As stdout is normally line buffered, add a newline to your printf so you can see output immmediately.

 printf("I am thread - %ld\n",my_id);
Community
  • 1
  • 1
nos
  • 223,662
  • 58
  • 417
  • 506
  • thanks for explaining the need of predicate for condition variable which I have used in first approach and you also suggest similar. I have one doubt or query - Don't you think there is a lot of wastage of CPU when it checks for the predicate ? BTW, although it seems logic is correct (I have used same logic except I have used only one state variable) but your code is not working. – bholanath Apr 08 '14 at 14:53
  • @bholanath There is no CPU wasted, pthread_cond_wait() blocks the thread. I don't know how you can make this work by having only one state variable (And I'm not sure what you mean by that either, it sounds like you have just 1 variable instead of an array like the wakeup array - that will not work). Note that the `wakeup[0] = 1;` in main() is rather important. – nos Apr 08 '14 at 15:04
  • I'm guessing it won'd work partially because of the `#define NTHREADS MULTIPLE_THREADS*64` macro, as it will not do what you want it to do. Always use parenthesis : `#define NTHREADS (MULTIPLE_THREADS*64)` – nos Apr 08 '14 at 15:27
  • I have changed the macro and now it is giving output. Thanks. BTW what is the use of multiple variable like array here as I am getting output with single variable (i.e. state) and check whether state == my_id or not ? – bholanath Apr 08 '14 at 15:58
  • yes, I suppose that's fine in this example if you only ever want sequential execution, only one variable with the executing id would do – nos Apr 08 '14 at 16:40