Search code examples
c++pthreadsmingwmutexmingw32

pthread_cond_wait wake many threads example


pthread_cond_wait wake many threads example

Code to wake up thread 1 & 3 on some broadcast from thread 0.

Setup: Win7 with mingw32, g++ 4.8.1 with mingw32-pthreads-w32 pthread condition variable

Solution: http://pastebin.com/X8aQ5Fz8

#include <iostream>
#include <string>
#include <list>
#include <map>
#include <pthread.h>
#include <fstream>

#include <sstream> // for ostringstream

#define N_THREAD 7

using namespace std;

// Prototypes
int main();
int scheduler();
void *worker_thread(void *ptr);
string atomic_output(int my_int, int thread_id);

// Global variables
//pthread_t thread0, thread1, thread2, thread3, thread4, thread5, thread6, thread7;

pthread_t m_thread[N_THREAD];
int count = 1;
pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;


// Main
int main() {

    cout << "Launching main. \n";

    //Start to monitor for exceptions
    register_exception_handler();

    //Start scheduler
    scheduler();

    return 0;
}


// Scheduler
int scheduler() {
    // Starting scheduler log file
    ofstream scheduler_log;
    scheduler_log.open ("scheduler_log.txt");
    //scheduler_log << "[Scheduler] Starting." << endl;
    cout << "[Scheduler] Starting.  \n";

    // Scheduler::Main Section

    int thread_id[N_THREAD];

    for(int i=0;i<N_THREAD;i++) {
        thread_id[i] = i;
        pthread_create( &m_thread[i], NULL, worker_thread, (void *) &thread_id[i]);
    }

    for(int i=0;i<N_THREAD;i++)
        pthread_join(m_thread[i], NULL);


    cout << "[Scheduler] Ending. \n";
    // Closing scheduler log file
    scheduler_log.close();

    return 0;
}

string atomic_output(int my_int, int thread_id) {
    ostringstream stm;
    stm << "Thread ";
    stm << thread_id;
    stm << ": ";


    //count fn
    stm << my_int;
    stm << "\n";


    //stm << "Finished. \n";

    return stm.str();
}

void *worker_thread(void *ptr) {
    string line;
    //int boo = 0;

    int thread_id = *(int *) ptr;

    //if(thread_id == 0)
    //  pthread_mutex_lock( &count_mutex );

    for(int i=0;i<10;i++) {
        //boo++;

        if (thread_id == 1) {

            pthread_mutex_lock(&count_mutex);
            while (count == 1) {
                cout << "[Thread 1] Before pthread_cond_wait...\n";
                pthread_cond_wait( &condition_var, &count_mutex );
                cout << "[Thread 1] After pthread_cond_wait...\n";
            }
            pthread_mutex_unlock(&count_mutex);

        }

        if (thread_id == 3) {

            pthread_mutex_lock(&count_mutex);
            while (count == 1) {
                cout << "[Thread 3] Before pthread_cond_wait...\n";
                pthread_cond_wait( &condition_var, &count_mutex );
                cout << "[Thread 3] After pthread_cond_wait...\n";
            }
            pthread_mutex_unlock(&count_mutex);
        }

        //count fn
        line = atomic_output(i, *(int *)ptr);
        cout << line;   

        if (i == 5) {
            if(thread_id == 0) {
                pthread_mutex_lock( &count_mutex );
                count = 0;
                pthread_mutex_unlock( &count_mutex );
                pthread_cond_broadcast(&condition_var);
            }
        }



    }

    //line = atomic_output(0, *(int *)ptr);
    //cout << line;
}

(old) -= What I've tried =-

*Edit: early problem in the code with while(0) instead of while(predicate). Keeping it there for easy reference with the comments.

Code 1: http://pastebin.com/rCbYjPKi

I tried to while(0) pthread_cond_wait( &condition_var, &count_mutex ); with pthread_cond_broadcast(&condition_var); ... The thread does not respect the condition.

Proof of condition non-respect : http://pastebin.com/GW1cg4fY

Thread 0: 0
Thread 0: 1
Thread 0: 2
Thread 0: 3
Thread 2: 0
Thread 6: 0
Thread 1: 0 <-- Here, Thread 1 is not supposed to tick before Thread 0 hit 5. Thread 0 is at 3.

Code 2: http://pastebin.com/g3E0Mw9W

I tried pthread_cond_wait( &condition_var, &count_mutex ); in thread 1 and 3 and the program does not return.

either thread 1, or thread 3 waits forever. Even using broadcast which says it should wake up all waiting threads. Obviously something is not working, code or lib?

More:

I've tried to unlock the mutex first, then broadcast. I've tried to broadcast then unlock. Both don't work.

I've tried to use signal instead of broadcast, same problem.

References that I can't make work (top google search)

http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032r/index.html

http://www-01.ibm.com/support/knowledgecenter/ssw_i5_54/apis/users_76.htm

Code 3: http://pastebin.com/tKP7F8a8

Trying to use a predicate variable count, to fix race problem condition. Still a problem, doesn't prevent thread1 and thread3 from running when thread0 is between 0 and 5.

What would be the code to wake up thread 1 & 3 on some function call from thread0


Solution

  • if(thread_id == 0)
        pthread_mutex_lock( &count_mutex );
    
    for(int i=0;i<10;i++) {
        //boo++;
    
        if (thread_id == 1) {
            while(0)
                pthread_cond_wait( &condition_var, &count_mutex );
        }
    

    None of this makes any sense. The correct way to wait for a condition variable is:

    pthread_mutex_lock(&mutex_associated_with_condition_variable);
    while (!predicate)
        pthread_cond_wait(&condition_variable, mutex_associated_with_condition_variable);
    

    Notice:

    1. The mutex must be locked.
    2. The predicate (thing you are waiting for) must be checked before waiting.
    3. The wait must be in a loop.

    Breaking any of these three rules will cause the kind of problems you are seeing. Your main problem is that you break the second rule, waiting even when the thing you want to wait for has already happened.