Click to See Complete Forum and Search --> : what happens if the main thread in not waiting for the signal and it receives one?


gopikb_1
November 29th, 2011, 04:35 AM
Hi
I need clarification regarding a code segment which in brief waitsfor a signal, but can receive signals from multiple threads. Just to clarify my stmt here is the code segment (outline)

process()
{
.... pthread_cond_wait.... //--> waiting for the signal
/*remaining part of code*/
}

callback_func1()
{
...pthread_cond_signal.. //--> assume thread1 calls this function and it signals the waiting thread
}

callback_func2()
{
...pthread_cond_signal.. //-->assume thread2 calls this function and it also signals thewaiting thread
}

I understand that callback functions gets executed under their respective calling thread scope i.e. callback_func1() when called will get executed as part of Thread1.
When Thread1 calls callback_func1() and it signals the condition, the main thread is awakened and continues to execute /*remaining part of code*/ in process() func.
At this point if Thread2 calls callback_func2() and it also signals the condition.
I am not very clear what happens now, Please clarify me in this scenario.
1. Since the main thread is already awakened and is not in wait state I am under the assumption that the signal by Thread2 after calling callback_func2() will be missed permanently.
2. How should I solve this problems, i.e. both the threads should have their signals processed. None of thread after sending the signal should miss out to execute the /*remaining part of code*/

Codeplug
November 30th, 2011, 02:23 PM
Condition variables should always be used with a "predicate loop":

pthread_mutex_lock(&Lock);
while (<predicate condition>)
pthread_cond_wait(&Cond, &Lock);
// condition signaled work
pthread_mutex_unlock(&Lock);

...

pthread_mutex_lock(&Lock);
<update predicate state>
pthread_cond_signal(&Cond);
pthread_mutex_unlock(&Lock);

So in this case the "predicate state" could be "number of threads that have signaled".
The "predicate loop" would then be "while the number of threads that have signaled is 0, wait".

int num_signaled = 0;
...
pthread_mutex_lock(&Lock);
while (num_signaled == 0)
pthread_cond_wait(&Cond, &Lock);
num_sigs_this_pass = num_signaled;
num_signaled = 0;
pthread_mutex_unlock(&Lock);
// process num_sigs_this_pass

...

pthread_mutex_lock(&Lock);
num_signaled += 1;
pthread_cond_signal(&Cond);
pthread_mutex_unlock(&Lock);

gg

Lindley
December 1st, 2011, 01:55 PM
That's over-complicating it slightly. He wants to wait for both threads to signal, and it shouldn't matter if they signal before or while the main thread is waiting, or in which order they signal.


int num_signaled = 0;
...
spawn thread 1
spawn thread 2 // must do these after initializing num_signaled to 0
...
pthread_mutex_lock(&Lock);
while (num_signaled != 2)
pthread_cond_wait(&Cond, &Lock);
pthread_mutex_unlock(&Lock);

...

// worker threads 1 and 2 can share this code
pthread_mutex_lock(&Lock);
num_signaled += 1;
pthread_cond_signal(&Cond);
pthread_mutex_unlock(&Lock);

Codeplug
December 1st, 2011, 02:48 PM
>> He wants to wait for both threads to signal ...
That's not what I parsed out from "2." in the first post.


...
pthread_mutex_lock(&Lock);
while (num_signaled != 2)
pthread_cond_wait(&Cond, &Lock);
pthread_mutex_unlock(&Lock);
...
That doesn't solve your interpretation of the problem. What if thread 1 signals twice (thread 2 hasn't signaled yet)? What if num_signaled becomes greater than 2?

If we have a thread 1 and thread 2, and both threads need to "signal" a 3rd thread to run - then using a barrier (http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_destroy.html) would be the easiest approach.

If we just need to make sure that "/*remaining part of code*/" is run for every callback_func1() and callback_func2() call - then the pseudo-code in post #2 shows one way to do that.

gg

gopikb_1
December 1st, 2011, 11:27 PM
Hi, Interpretation of "gg" reg point 2 is what I need.
The code outline which I mentioned is of the application, The app calls a library function which is inturn responsible for spawning the threads, the no. of threads spawned is dynamic. Suppose for e.g. initializtion and events represent the 2 callbacks. So each thread calls the callback functions accordingly when there are initialized (callback_func1() ) or they receive events(callback_func2() ). The number of times and the order in which callback_func1() and callback_func2() is called is unpredictable. Also on the app side I am not suppossed to maintain which threads "init" or "event" is being received.

"gg", can you please elaborate on your post#2 example, I am new to multithreading and mutex condition variables. Could not get the purpose of "num_sigs_this_pass"

Codeplug
December 2nd, 2011, 11:09 AM
>> please elaborate on your post#2 example

int num_signaled = 0;
pthread_cond_t Cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t Lock = PTHREAD_MUTEX_INITIALIZER;

void process()
{
...
pthread_mutex_lock(&Lock);
while (num_signaled == 0)
pthread_cond_wait(&Cond, &Lock); // this releases Lock while waiting

int num_sigs_this_pass = num_signaled;
num_signaled = 0;
pthread_mutex_unlock(&Lock);

// we have been signaled 'num_sigs_this_pass' times
for (int n = 0; n < num_sigs_this_pass; ++n)
/*remaining part of code*/
...
// loop back to top and do it again
}

void signal_process()
{
pthread_mutex_lock(&Lock);
num_signaled += 1;
pthread_cond_signal(&Cond);
pthread_mutex_unlock(&Lock);
}

void callback_func1() {signal_process();}
void callback_func2() {signal_process();}


>> Could not get the purpose of "num_sigs_this_pass"
The "num_signaled" variable can only be accessed while "Lock" is acquired. While "Lock" is acquired, "num_signaled" is saved off and reset back to 0. Then once "Lock" is released, the code processes the "num_sigs_this_pass" number of signals.

Without "num_sigs_this_pass", the code would have to process "/*remaining part of code*/" with "Lock" acquired - which is unnecessary. "Lock" should only be used with "Cond", and to protect "num_signaled". In general, the duration that a lock remains acquired should be minimized.

gg

amit21
December 15th, 2011, 12:30 AM
Hello every one, if any one find any flaws in my solution please point me out

i guess you want proceed further only when you got a signal from both the thread, and both thread are executing diffrent functions

pthread_t thread1;
pthread_t thread2;

int var_thread1 = 0;

int var_thread2 = 0;


process()
{

pthread_mutex_lock(&lock);
while(var_thread1 * var_thread2 = 1)
pthread_cond_wait(&cond,&lock);
...................
...................
pthread_mutex_unlock(&lock);

}


thread1_Fun()
{
var_thread1 = 1;
pthread_cond_signal(&cond);
}

thread2_Fun()
{
var_thread2 = 1;
pthread_cond_signal(&cond);
}

Codeplug
December 15th, 2011, 11:55 AM
>> any flaws in my solution please point me out
The while loop in process() is wrong.
You need to lock/unlock in thread1_Fun() and thread2_Fun().

With that fixed, the code will block process() until thread1_Fun() and thread2_Fun() have been called at least once, then it never blocks on the condition again.

If var_thread1 and var_thread2 were reset back to 0 before process() unlocks, that wouldn't be very useful either. What if thread1_Fun() is called N times and thread2_Fun() is called once? How many times should process() be "signaled" in that case: 1 or N+1 times? If the answer is 1, then a barrier (http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_destroy.html) is the best tool for the job. If the answer N+1 then the code in post #6 can handle that.

gg