LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
LinkBack Search this Thread
Old 07-15-2009, 05:15 PM   #1
brfindla
LQ Newbie
 
Registered: Apr 2004
Location: Merrimack, NH
Posts: 13

Rep: Reputation: 0
Posix thread question - pthread_cond_wait


I am not a seasoned threads programmer, so please be kind if this sounds ignorant. It probably is. I have read and studied for hours with no solution.

I am trying to create n number of threads, then have them wait for a condition to occur. There is some significant code running prior to waiting for this condition, and alot of threads being created, so when I try to trigger the condition on n number of threads shortly after thread creation, there appears to be a race condition. All of the threads do not always execute. All have unique signal_request, but share the same mutex.

mythread()
.....

// lots of stuff done here

rc = pthread_mutex_lock(&xmutex);
if (rc) {
perror("pthread_mutex_lock");
pthread_exit(NULL);
}

rc = pthread_cond_wait(&signal_request[tnum], &xmutex);
if (rc == 0) {
printf("Thread Number %d (tid %ld)woke up\n",
tnum, pthread_self());
// other stuff I want to do..
}
pthread_mutex_unlock(&xmutex);
}



My questions are;
(1) if the condition (&signal_request[tnum]) occurs prior to blocking on the pthread_cond_wait() is it true that it will not be recognized?
(2) How can I know that it is "safe" to send the condition so that it will be recognized?

Note: If I place sleep() after the thread creation and before sending the condition, it works, but obviously it is masking a race condition. I expect there are times when if enough threads are created that will fail too. Is there a way to do this, or should I look other alternatives. This may be an ignorant statement, but from what I can understand, without knowing the thread has executed to the pthread_cond_wait statement, this is at best unreliable, at worst, useless.

Thanks in advance.. always trying to learn a few things and this has been a good forum.

Brian
 
Old 07-15-2009, 07:14 PM   #2
wje_lq
Member
 
Registered: Sep 2007
Location: Mariposa
Distribution: Debian lenny, Slackware 12
Posts: 805

Rep: Reputation: 161Reputation: 161
Quote:
Originally Posted by brfindla View Post
when I try to trigger the condition on n number of threads shortly after thread creation
If I can guess correctly from your code, variable tnum is a thread number, and you do one triggering for each subsidiary thread that you want to wake up. This is a good thing. (It would be a confusing thing if you were to want to do one trigger and expect all the subsidiary threads to wake up.)
Quote:
Originally Posted by brfindla View Post
there appears to be a race condition.
This is a quite common indication that pthreads are not being used properly.
Quote:
Originally Posted by brfindla View Post
(1) if the condition (&signal_request[tnum]) occurs prior to blocking on the pthread_cond_wait() is it true that it will not be recognized?
No, not if you use pthreads correctly.
Quote:
Originally Posted by brfindla View Post
(2) How can I know that it is "safe" to send the condition so that it will be recognized?
It will be safe from the very beginning, even before you initialize the subsidiary threads, provided you use pthreads properly.

Before I go into details on your questions, may I make a suggestion? Use an array of mutexes, so there's a one-to-one correspondence between mutexes and condition variables. That's the ordinary way of doing what you seem to be doing. You could bundle it all up in one mutex if you want, but that tends to be a bad habit, because it can reduce the amount of parallelism among threads.

Here's an important point. To use condition variables for coordination among threads, you need three things:
  1. a mutex;
  2. a corresponding condition variable; and
  3. a corresponding condition that you can actually test.
For example, suppose that a subsidiary thread is supposed to do something if global variable alpha is greater than or equal to global variable beta.

Your primary thread grabs the mutex protecting alpha and beta, changes one or both of those variables, and releases the mutex. It then calls pthread_cond_signal() to wake up the subsidiary thread.

Your subsidiary thread figures out when to run by doing the following things, but in a particular sequence which I'll describe in a moment:
  1. testing the condition itself;
  2. using the mutex; and
  3. using the condition variable.
Here's what your subsidiary thread should do:
  1. Lock the mutex.
  2. Test the condition. If the test passes, then go to step 5. Note that this covers the case of the condition being true even before your subsidiary thread starts!
  3. Since the test does not pass, do a pthread_cond_wait(). Do not unlock the mutex before you do this; the pthread_cond_wait() will do this atomically with the waiting. If you unlocked the mutex first, it could be that some other thread makes the condition true, and then you do the pthread_cond_wait() to wait for a condition that's already true. Deadlock! So let the pthread_cond_wait() unlock the mutex for you.
  4. When the subsidiary thread wakes up from the pthread_cond_wait(), the mutex will have been locked for you again. (Again, atomicity is important). But there's no guarantee that the condition will have actually changed. Go back to step 2 (which relies on the mutex being locked) and test the condition again.
  5. Do what you need to do with the condition being true. Presumably you will, in the process, make the condition false. If you didn't do that, your thread would then most likely wake up again and do everything a second time!
  6. Unlock the mutex. Go back to step 1 to wait for the condition to be true again.
In your case, where the condition to be tested would be very simple, I would recommend an array of elements of type short, initialized to zero. When you want to wake up a subsidiary thread, set its element in this array to nonzero. Make the subsidiary thread check this element for nonzero. When the subsidiary thread is finished processing, it should set the element to zero again.

A by-product of this arrangement is that your primary thread can lock the mutex for a given thread and test that element in this array to see whether the thread is currently running. (And then, I hope, unlock the corresponding mutex again!)

This whole thing probably seems like a magical incantation to you, something you do because I've advised you to do it. If you don't have a thorough understanding of why you need to do these things in the specified order, please do one of two things.
  1. If you are taking a course that uses POSIX threads because the course is required, and you'll never use pthreads again, talk to your professor or teaching assistant or an uebergeek fellow student to clarify why you'd want to do things as specified above.
  2. If, on the other hand, you're going to use POSIX threads in an ongoing project, or later in your career, or you are simply curious about how it works so at least you don't write the kind of synchronization bug that might show up once in a million years (Murphy's law, indeed), then run, don't walk, to your nearest bookseller and order the fine book Programming with POSIX Threads, authored by David R. Butenhof and published by Addison Wesley. Then instead of going on that date with your main squeeze this Saturday, invite her over to your place with a good novel while you read this book pretty much from cover to cover.

    (My experience with the corresponding O'Reilly book is that it's arguably complete, but so inadequate that it's downright dangerous.)
Hope this helps.
 
Old 07-15-2009, 09:23 PM   #3
brfindla
LQ Newbie
 
Registered: Apr 2004
Location: Merrimack, NH
Posts: 13

Original Poster
Rep: Reputation: 0
wje_lq
Can I tell you that you are a god like figure to me? That was really a considered response. No joke I am really grateful, I can see just to write it must have taken some time, to learn it was probably a decade. I think I've learned more from reading your post that what I got out of hours and several books and websites. I have been working on this since yesterday and really want to learn how to do it right and not hack it. The info is not out there in an easy to find form, but perhaps that's why they pay good software engineers decent salaries. It's a great response more that I could have expected, I really thank you a lot. I hope this gets in some easy to search archives.

Thanks!

Brian
 
Old 07-15-2009, 09:33 PM   #4
brfindla
LQ Newbie
 
Registered: Apr 2004
Location: Merrimack, NH
Posts: 13

Original Poster
Rep: Reputation: 0
Just bought the book.. it's funny, the author lives (or lived) in my small city. Thanks again.
 
  


Reply

Tags
posix


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Simple posix thread jabbertrex Programming 3 04-14-2007 11:29 PM
Thread Scheduling using POSIX THREAD rameshtekumudi Programming 3 09-01-2006 10:47 AM
POSIX thread Ivan Lee Programming 2 03-28-2003 03:54 AM
RT Posix thread permissions spaceape Programming 0 01-23-2003 08:50 AM
posix thread sulo Programming 1 02-28-2002 07:41 PM


All times are GMT -5. The time now is 06:49 PM.

Main Menu
 
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: @linuxquestions
Open Source Consulting | Domain Registration