-1

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

Lazik
  • 2,480
  • 2
  • 25
  • 31
  • Can we see the code? Pretty please? – wavemode Apr 08 '15 at 06:13
  • Added the code directly in the question :) – Lazik Apr 08 '15 at 06:15
  • Can you just search for examples how how to use condition variables? Or ask how to use them and leave out a whole bunch of code that really isn't relevant to your question. – David Schwartz Apr 08 '15 at 06:18
  • I did, none of them work for more than 2 threads. Added reference at the end of question... – Lazik Apr 08 '15 at 06:19
  • There are a couple of problems that stands out. The first is that you assume that `pthread_t` is an integer type. The second is a race-condition, in that you assume thread "0" would be the first to run and so successfully lock the `count_mutex` first. And why, if you already have the "integer" `thread_id` do you use `ptr` when calling `atomic_output` (which is weirdly named as it does no output). – Some programmer dude Apr 08 '15 at 06:21
  • @JoachimPileborg No you're wrong, it's not assumed to be an integer. And also no, it is not assumed to be called the first. It is assumed that once thread 0: 0 thicked once till it says thread0: 5, there should be no thread1 or thread3 in between. Which there are. – Lazik Apr 08 '15 at 06:27
  • Ah, please disregard the id issue from my comment, you're using to (deceptively named I would say) different arrays. So `thread_id` is not really the *thread* id, it's just your own "id". However the race condition is still there, there's no guarantee that all the threads will be executed in the order you create them in, or that they will run until the check for thread `0` before being preemptied, which mean any other thread may be running to the `pthread_cond_wait` call before thread `0`, which assumes that the mutex is *locked* anyway. – Some programmer dude Apr 08 '15 at 06:34
  • I've added code 3, which use an extra state_variable protected by the count_mutex. Still have problems, the condition is not respected. – Lazik Apr 08 '15 at 07:04
  • Your code 3 still has `while (0)` loops (which make the code not execute) and has an `if` to check the predicate rather than a `while`. You unlock the `mutex` as soon as you wake, which also doesn't make sense for your use case (don't you need to change the predicate for the next thread?). Also, all your threads are checking the same predicate the same way, so why would you expect them to operate in any particular order? What enforces the ordering? – David Schwartz Apr 08 '15 at 07:29
  • Oups, mindless mistake while(0) -.- . There's no ordering, so really it`s just exclude thread 1 and 3 from executing until thread0 is at i=5. – Lazik Apr 08 '15 at 07:32
  • @DavidSchwartz Finally got it working, thanks for your help. http://pastebin.com/a9bdWMN3 I'm still unclear on a few details but I'll play with mutex and try to understand in more details. – Lazik Apr 08 '15 at 07:50
  • @Lazik That code looks much better. You're not really doing all that much, since you just release the mutex once you detect the predicate. But what you are doing, you are doing correctly. – David Schwartz Apr 08 '15 at 08:42

1 Answers1

2
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.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Can you edit the code to show how to do it? I understand what you are saying, it just doesn't help me achieve my goal. It is also my understanding that cond_wait is supposed to give back time to the cpu. So if you while(0) it does not. Plus if you try to acquire the lock, and fail it's going to wait for it too, right? – Lazik Apr 08 '15 at 06:28
  • @Lazik Okay, I assumed too much. You don't get condition variables at all. Forget about your code. Forget about your question. Forget about my answer. Find some example code that uses condition variables that you understand. The reason `while(0)` is wrong is that you're have to wait *for* something. – David Schwartz Apr 08 '15 at 06:29
  • Yea wish I could, I searching for it - but can't find any that do what I want. That's why I posted here. Perhaps what I am looking for is not a condition-mutex paradigm. – Lazik Apr 08 '15 at 06:31
  • I thought it was waiting for a cond_broadcast? – Lazik Apr 08 '15 at 06:32
  • 1
    @Lazik [This](https://github.com/angrave/SystemProgramming/wiki/Synchronization,-Part-5:-Condition-Variables) might help you. No, it doesn't wait for a cond_broadcast. The broadcast informs the thread that the thing it's waiting for may have happened, but it can't be the thing the thread is waiting for because that has to have a state (either the thing happened or the thing didn't happen, so two states) and condition variables are stateless. – David Schwartz Apr 08 '15 at 06:33
  • 1
    If you're waiting for something, then either that something has happened or it hasn't. And whether or not that something has happened has to be stored somewhere so that you know whether to wait or not. That thing is called the "predicate", and you have to implement it. The whole purpose of condition variables is to provide an atomic "unlock and wait" operation to fix the race condition where the thing happens just as you try to wait for it. If this doesn't all make sense to you, you don't understand condition variables well enough to write code using them. – David Schwartz Apr 08 '15 at 06:35
  • Uh well that code was supposed to be an experiment to understand condition variables... Why do we give cond_wait the mutex ? I thought when you get the broadcast, check if the mutex is unlocked, if so continue. If the mutex is lock, continue to wait. That's what I don't understand. I thought the mutex IS the predicate, is that wrong? If so what is the purpose of the mutex in that case? – Lazik Apr 08 '15 at 06:47
  • @Lazik The mutex protects the predicate since the predicate has to be shared between threads that check the predicate and threads that change the predicate. The predicate is the thing you're waiting for, which depends on what you're using the condition variable to do. – David Schwartz Apr 08 '15 at 07:25