Re: [LAD] question about multithreaded externals in Pd

From: Robin Gareus <robin@email-addr-hidden>
Date: Sat Oct 02 2010 - 04:00:54 EEST

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@email-addr-hidden
> http://lists.linuxaudio.org/listinfo/linux-audio-dev
_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@email-addr-hidden
http://lists.linuxaudio.org/listinfo/linux-audio-dev
Received on Sat Oct 2 04:15:02 2010

This archive was generated by hypermail 2.1.8 : Sat Oct 02 2010 - 04:15:02 EEST