[LAD] question about multithreaded externals in Pd

Ivica Ico Bukvic ico at vt.edu
Sat Oct 2 01:13:02 UTC 2010


Many thanks for the clarification Robin, really appreciate it!

One more thing I realized, isn't the secondary thread effectively blocking the lock on the main thread because the mutex_lock is placed before the cond call or is this the right way to do it? Namely, should secondary thead have the following structure:

While loop {
	mutex_lock
	state cond <--this is where the thread supposedly waits (does this have to be "while" loop or a simple if will do as is the case in my code?)
	do something
	mutex_unlock
}
Thread exit

Ico

> -----Original Message-----
> From: Robin Gareus [mailto:robin at gareus.org]
> Sent: Friday, October 01, 2010 9:01 PM
> To: Ivica Ico Bukvic
> Cc: linux-audio-dev at lists.linuxaudio.org
> Subject: Re: [LAD] question about multithreaded externals in Pd
> 
> Hi Ico,
> 
> just quick:
> 
> pthread_create() returns after the thread context has been created; but
> the actual thread-function is not run directly.
> 
> The main function may continue before the actual thread is run.
> 
> In your case the pd_cwiid_doConnect() can be called before the
> pd_cwiid_pthreadForAudioUnfriendlyOperations() enters the while() loop.
> 
> That seems to be a problem - it's too much code to dig though for me at
> the moment to tell why this is so -  but since usleep() seems to solve
> the issue, it probably is. (quick check: does it also crash if you
> usleep() after the if (argc==2) {}; just before the return(x); ?
> 
> `man 3 pthread_yield` is better that usleep(). it's basically a
> usleep(minimum-time-needed-to-run-other-threads).
> 
> Another option is to wait after thread-creation in the parent on a
> barrier or lock that is released by the child-thread when it starts.
> 
> 2c,
> robin
> 
> On 10/02/10 02:36, Ivica Ico Bukvic wrote:
> > Hi all,
> >
> > I am wondering if anyone can shed some light on the following
> > predicament. I am by no means a multi-threading guru so any insight
> > would be most appreciated.
> >
> > The following are relevant excerpts from the code of an external. AFAIK
> > the external initializes mutex and cond and spawns a secondary worker
> > thread that deals with audio-unfriendly (xrun-causing) write operations
> > to the wiimote and terminates it when the object is destructed waiting
> > for the thread to join back and then destroying the mutex.
> >
> > Now, if I add a bit of usleep right after the thread has been spawned
> as
> > part of the constructor (as included below) the external seems very
> > stable (e.g. cutting and pasting it as fast as keyboard allows, or in
> > other words constructing and destructing instances of it as fast as
> > possible does not result in a crash). Yet, when one does not use usleep
> > right after spawning the secondary (worker) thread in the constructor,
> > the whole thing is very crash-prone, almost as if the spawning of thread
> > does not go well unless given adequate time to do get things all into
> > sync, so to say, even though this makes to me no sense as the way I
> > understand it the constructor does not move ahead until
> pthread_create
> > does not return a value (which in this case I am not bothering to read).
> >
> > Curiously, when not using usleep, a crash may occur right at creation
> > time, at any point while the object exists, and even as late as during
> > its destruction. Any ideas?
> >
> > P.S. I am also including the entire file for those interested in trying
> > it out.
> >
> > Best wishes,
> >
> > Ico
> >
> > Relevant excerpts (in random order and incomplete to allow for
> greater
> > legibility):
> >
> > //struct defining the object
> > typedef struct _wiimote
> > {
> > 	t_object x_obj; // standard pd object (must be first in struct)
> >
> > 	...
> >
> > 	//Creating separate threads for actions known to cause sample
> drop-outs
> > 	pthread_t unsafe_t;
> > 	pthread_mutex_t unsafe_mutex;
> > 	pthread_cond_t unsafe_cond;
> >
> > 	t_float unsafe;
> >
> > 	...
> >
> > 	t_float led;
> >
> > 	...
> >
> > } t_wiimote;
> >
> >
> > //constructor
> > static void *pd_cwiid_new(t_symbol* s, int argc, t_atom *argv)
> > {
> > 	...
> >
> > 	x->led = 0;
> >
> > 	// spawn threads for actions known to cause sample drop-outs
> > 	threadedFunctionParams rPars;
> > 	rPars.wiimote = x;
> > 	pthread_mutex_init(&x->unsafe_mutex, NULL);
> > 	pthread_cond_init(&x->unsafe_cond, NULL);
> > 	pthread_create( &x->unsafe_t, NULL, (void *)
> > &pd_cwiid_pthreadForAudioUnfriendlyOperations, (void *) &rPars);
> >
> > 	//WHY IS THIS NECESSARY? I thought that pthread_create call will
> first
> > finish spawning thread before proceeding
> > 	usleep(100); //allow thread to sync (is there a better way to do
> this?)
> >
> > 	...
> > }
> >
> > //destructor
> > static void pd_cwiid_free(t_wiimote* x)
> > {
> > 	if (x->connected) {
> > 		pd_cwiid_doDisconnect(x); //this one has nothing to do
> with thread but
> > rather disconnects the wiimote
> > 	}
> >
> > 	x->unsafe = -1; //to allow secondary thread to exit the while loop
> >
> > 	pthread_mutex_lock(&x->unsafe_mutex);
> > 	pthread_cond_signal(&x->unsafe_cond);
> > 	pthread_mutex_unlock(&x->unsafe_mutex);
> >
> > 	pthread_join(x->unsafe_t, NULL);
> > 	pthread_mutex_destroy(&x->unsafe_mutex);
> >
> > 	...
> > }
> >
> > //worker thread
> > void pd_cwiid_pthreadForAudioUnfriendlyOperations(void *ptr)
> > {
> > 	threadedFunctionParams *rPars = (threadedFunctionParams*)ptr;
> > 	t_wiimote *x = rPars->wiimote;
> > 	t_float local_led = 0;
> > 	t_float local_rumble = 0;
> > 	unsigned char local_rpt_mode = x->rpt_mode;
> >
> > 	while(x->unsafe > -1) {
> > 		pthread_mutex_lock(&x->unsafe_mutex);
> > 		if ((local_led == x->led) && (local_rumble == x->rumble)
> &&
> > (local_rpt_mode == x->rpt_mode)) {
> > 			pthread_cond_wait(&x->unsafe_cond, &x-
> >unsafe_mutex);
> > 		}
> >
> > 		if (local_led != x->led) {
> > 			local_led = x->led;
> > 			//do something
> > 			}
> > 		}
> > 		if (local_rumble != x->rumble) {
> > 			local_rumble = x->rumble;
> > 			//do something else
> > 		}
> >
> > 		...
> >
> > 		pthread_mutex_unlock(&x->unsafe_mutex);
> > 	}
> > 	pthread_exit(0);
> > }
> >
> > //an example of how the thread is affected by the main thread
> > void pd_cwiid_setLED(t_wiimote *x, t_floatarg f)
> > {
> > 	if (x->connected) {
> > 		x->led = f;
> >
> > 		pthread_mutex_lock(&x->unsafe_mutex);
> > 		pthread_cond_signal(&x->unsafe_cond);
> > 		pthread_mutex_unlock(&x->unsafe_mutex);
> > 	}
> > }
> >
> >
> >
> >
> > _______________________________________________
> > Linux-audio-dev mailing list
> > Linux-audio-dev at lists.linuxaudio.org
> > http://lists.linuxaudio.org/listinfo/linux-audio-dev




More information about the Linux-audio-dev mailing list