Date: Wed, 23 Feb 2005 08:14:18 +0200 From: Giorgos Keramidas <keramida@ceid.upatras.gr> To: Jonathon McKitrick <jcm@FreeBSD-uk.eu.org> Cc: freebsd-questions@freebsd.org Subject: Re: Best way to share data between threads Message-ID: <20050223061418.GB638@gothmog.gr> In-Reply-To: <20050223035804.GA95877@dogma.freebsd-uk.eu.org> References: <20050222055000.GA49525@dogma.freebsd-uk.eu.org> <20050222063810.GA1784@gothmog.gr> <20050222121911.GA63213@dogma.freebsd-uk.eu.org> <20050222124244.GA80450@orion.daedalusnetworks.priv> <20050223035804.GA95877@dogma.freebsd-uk.eu.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On 2005-02-23 03:58, Jonathon McKitrick <jcm@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050223061418.GB638>