// simplethread xplatform/mach-o // based on simplethread by jkc // -----------------------------+---------------+---------------------------- // create a Headers folder in /Library/Frameworks/MaxAPI.framework/Versions/A/ // copy the files from MaxMSP-SDK/4.5 headers/c74support/max-includes into the Headers folder. // then symlink Headers to /Library/Frameworks/MaxAPI.framework/ // now #include works, and xcode knows about the headers for def'n searching etc. #include #include #include // -----------------------------+---------------+---------------------------- typedef struct _simplethread { t_object x_ob; // standard max void *x_systhread; // thread id bool x_systhread_cancel; // thread cancel flag void *x_qelem; // for message passing between threads void *x_outlet; int foo; // simple data to pass between threads } t_simplethread; // -----------------------------+---------------+---------------------------- void *simplethread_class; void simplethread_bang(t_simplethread *x); void simplethread_stop(t_simplethread *x); void simplethread_cancel(t_simplethread *x); void *simplethread_threadproc(t_simplethread *x); void simplethread_qfn(t_simplethread *x); void simplethread_assist(t_simplethread *x, void *b, long m, long a, char *s); void simplethread_free(t_simplethread *x); void *simplethread_new(void); // -----------------------------+---------------+---------------------------- int main(void) { setup((t_messlist **)&simplethread_class, (method)simplethread_new, (method)simplethread_free, (short)sizeof(t_simplethread), 0L, 0); addbang((method)simplethread_bang); addmess((method)simplethread_cancel, "cancel", 0); addmess((method)simplethread_assist, "assist", A_CANT, 0); return 0; } // -----------------------------+---------------+---------------------------- void simplethread_bang(t_simplethread *x) { simplethread_stop(x); // kill thread if, any // create new thread + begin execution if (x->x_systhread == NULL) { // stacksize, priority and flags are ignored for now. systhread_create((method) simplethread_threadproc, x, 0, 0, 0, &x->x_systhread); } } // -----------------------------+---------------+---------------------------- void simplethread_stop(t_simplethread *x) { unsigned int ret; if (x->x_systhread) { critical_enter(0); x->x_systhread_cancel = true; // tell the thread to stop critical_exit(0); systhread_join(x->x_systhread, &ret); // wait for the thread to stop x->x_systhread = NULL; } } // -----------------------------+---------------+---------------------------- void simplethread_cancel(t_simplethread *x) { simplethread_stop(x); // kill thread if, any outlet_anything(x->x_outlet, gensym("cancelled"), 0, NULL); } // -----------------------------+---------------+---------------------------- void * simplethread_threadproc(t_simplethread *x) { bool cancel = false; // loop until told to stop while (1) { critical_enter(0); cancel = x->x_systhread_cancel; // test if we're being asked to die x->foo++; // fiddle with data critical_exit(0); qelem_set(x->x_qelem); // notify main thread using qelem mechanism // do this _after notifying main thread, otherwise we lose this // loop's worth of "data" if (cancel) break; systhread_sleep(1000); // sleep a bit } critical_enter(0); x->x_systhread_cancel = false; // reset cancel flag for next time, in case // the thread is created again critical_exit(0); systhread_exit(NULL); // this can return a value to systhread_join(); return NULL; } // -----------------------------+---------------+---------------------------- // triggered by the helper thread void simplethread_qfn(t_simplethread *x) { int myfoo; critical_enter(0); myfoo = x->foo; // manipulate threaded data critical_exit(0); outlet_int(x->x_outlet, myfoo); } // -----------------------------+---------------+---------------------------- void simplethread_assist(t_simplethread *x, void *b, long m, long a, char *s) { if (m==1) sprintf(s,"how many licks does it take?"); else if (m==2) sprintf(s,"report when done/cancelled"); } // -----------------------------+---------------+---------------------------- void simplethread_free(t_simplethread *x) { simplethread_stop(x); if (x->x_qelem) qelem_free(x->x_qelem); } // -----------------------------+---------------+---------------------------- void *simplethread_new(void) { t_simplethread *x; x = (t_simplethread *)newobject(simplethread_class); x->x_outlet = outlet_new(x,NULL); x->x_qelem = qelem_new(x,(method)simplethread_qfn); x->x_systhread = NULL; x->foo = 0; return(x); }