From owner-freebsd-questions@FreeBSD.ORG Wed Feb 23 06:15:40 2005 Return-Path: Delivered-To: freebsd-questions@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id E7F8716A4F6 for ; Wed, 23 Feb 2005 06:15:39 +0000 (GMT) Received: from aiolos.otenet.gr (aiolos.otenet.gr [195.170.0.23]) by mx1.FreeBSD.org (Postfix) with ESMTP id D327B43D1D for ; Wed, 23 Feb 2005 06:15:37 +0000 (GMT) (envelope-from keramida@ceid.upatras.gr) Received: from gothmog.gr (patr530-b167.otenet.gr [212.205.244.175]) j1N6ERi5011639; Wed, 23 Feb 2005 08:14:28 +0200 Received: from gothmog.gr (gothmog [127.0.0.1]) by gothmog.gr (8.13.3/8.13.3) with ESMTP id j1N6EIQp001389; Wed, 23 Feb 2005 08:14:18 +0200 (EET) (envelope-from keramida@ceid.upatras.gr) Received: (from giorgos@localhost) by gothmog.gr (8.13.3/8.13.3/Submit) id j1N6EIQH001388; Wed, 23 Feb 2005 08:14:18 +0200 (EET) (envelope-from keramida@ceid.upatras.gr) Date: Wed, 23 Feb 2005 08:14:18 +0200 From: Giorgos Keramidas To: Jonathon McKitrick Message-ID: <20050223061418.GB638@gothmog.gr> 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> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20050223035804.GA95877@dogma.freebsd-uk.eu.org> cc: freebsd-questions@freebsd.org Subject: Re: Best way to share data between threads X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 Feb 2005 06:15:40 -0000 On 2005-02-23 03:58, Jonathon McKitrick 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