[LAD] question about multithreaded externals in Pd

Robin Gareus robin at gareus.org
Sat Oct 2 01:00:54 UTC 2010


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