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:ro...@gareus.org] > Sent: Friday, October 01, 2010 9:01 PM > To: Ivica Ico Bukvic > Cc: linux-audio-dev@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@lists.linuxaudio.org > > http://lists.linuxaudio.org/listinfo/linux-audio-dev _______________________________________________ Linux-audio-dev mailing list Linux-audio-dev@lists.linuxaudio.org http://lists.linuxaudio.org/listinfo/linux-audio-dev