Best way to share data between threads
Giorgos Keramidas
keramida at ceid.upatras.gr
Wed Feb 23 06:15:40 GMT 2005
On 2005-02-23 03:58, Jonathon McKitrick <jcm at FreeBSD-uk.eu.org> wrote:
>On Tue, Feb 22, 2005 at 02:42:44PM +0200, Giorgos Keramidas wrote:
>: 1) Explicit notification using a condition variable.
>:
>: The first can be accomplished by associating a pthread_cond_t with the
>
> I think this is the approach I will use. As a matter of fact, I added it
> today for a different, more limited use, and it worked well. We have an
> instrument that needs firmware ftp'ed to it after a cold start, and I placed
> that into a pthread. I'll try the data acq thread soon.
>
> The only problem is that pthread_join doesn't seem to have a timeout
> feature. So if the thread hangs, I have no way of knowing.
True. I usually get around this by polling on a thread flag until its
state changes as expected or a timeout occurs.
struct thread_data {
pthread_mutex_t td_lock;
pthread_t td_id;
int td_flags;
};
#define TDF_SPAWNING (1<<0) /* Thread is now spawning */
#define TDF_ACTIVE (1<<1) /* If set, thread is active */
#define TDF_CLOSE (1<<2) /* If set, thread closes */
#define TDF_CLOSING (1<<3) /* Thread in close process */
The main thread that needs to know if a thread is active, keeps a list
of thread_data structures around and passes pointers to these structures
to pthread_create() as the thread 'arg'.
Before calling pthread_create(), the main thread initializes a new
thread_data structure and sets its TDF_SPAWNING flag. This way, even if
the spawned thread takes a long time to start, the thread_data won't be
ripped off from under its feet while it is still spawning.
Then pthread_create() starts the new thread:
struct thread_data *td;
if (pthread_create(&(td->td_id), NULL, thread_main, td) != 0)
die();
The pthread_main() function takes care of changing the state of the
thread_data from TDF_SPAWNING to TDF_ACTIVE:
void *
thread_main(void *arg)
{
struct thread_data *td = (struct thread_data *)arg;
if (td == NULL)
return (NULL);
if (pthread_mutex_lock(&(td->td_lock)) != 0)
return (NULL);
td->td_flags |= TDF_ACTIVE;
td->td_flags &= ~(TDF_SPAWNING);
if (pthread_mutex_unlock(&(td->td_lock)) != 0)
panic();
Then the thread_main() function can go on doing other things, waiting
for its TDF_CLOSE flag to be set. That is an indication that the thread
should start cleaning up and stop running. As soon as the thread
notices TDF_CLOSE is set, it locks thread_data, sets TDF_CLOSING and
clears TDF_CLOSE. Then thread_data can be unlocked again, the thread
can clean up, eventually ending up at the final part:
if (pthread_mutex_lock(&(td->td_lock)) != 0)
error();
td->td_flags &= ~(TDF_ACTIVE | TDF_CLOSING);
if (pthread_mutex_unlock(&(td->td_lock)) != 0)
error();
return (arg);
Done. The fact that TDF_ACTIVE is no longer set, means that the thread
has already exited, so its safe to call pthread_join() on its td->td_id
and it won't block indefinitely.
- Giorgos
More information about the freebsd-questions
mailing list