From 99a29c1926eee84f100ad9ea59a8c33f7878c342 Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Sun, 22 Dec 2002 01:28:34 +0000 Subject: "no message" svn path=/trunk/; revision=306 --- externals/grill/flext/flext.cw | Bin 202097 -> 204177 bytes externals/grill/flext/readme.txt | 19 +- externals/grill/flext/source/flbase.h | 4 +- externals/grill/flext/source/flclass.h | 99 ++------- externals/grill/flext/source/fldefs.h | 50 ++--- externals/grill/flext/source/fldsp.h | 2 +- externals/grill/flext/source/flext.cpp | 14 +- externals/grill/flext/source/flext.h | 17 +- externals/grill/flext/source/flout.cpp | 49 ++--- externals/grill/flext/source/flprefix.h | 16 ++ externals/grill/flext/source/flsupport.h | 235 +++++++++++++++++++--- externals/grill/flext/source/flthr.cpp | 230 +++++++++++++++------ externals/grill/flext/tutorial/maxmsp/ex-thread1 | Bin 0 -> 1004 bytes externals/grill/flext/tutorial/maxmsp/ex-thread2 | Bin 0 -> 874 bytes externals/grill/flext/tutorial/pd/ex-thread1.pd | 86 ++++---- externals/grill/flext/tutorial/readme.txt | 2 +- externals/grill/flext/tutorial/thread1/main.cpp | 8 +- externals/grill/flext/tutorial/thread1/thread1.cw | Bin 68426 -> 68426 bytes externals/grill/flext/tutorial/thread2/main.cpp | 18 +- externals/grill/flext/tutorial/thread2/thread2.cw | Bin 68426 -> 68426 bytes 20 files changed, 534 insertions(+), 315 deletions(-) create mode 100755 externals/grill/flext/tutorial/maxmsp/ex-thread1 create mode 100755 externals/grill/flext/tutorial/maxmsp/ex-thread2 (limited to 'externals/grill/flext') diff --git a/externals/grill/flext/flext.cw b/externals/grill/flext/flext.cw index 120b5560..21096612 100644 Binary files a/externals/grill/flext/flext.cw and b/externals/grill/flext/flext.cw differ diff --git a/externals/grill/flext/readme.txt b/externals/grill/flext/readme.txt index 7fbcc8dc..eefd0260 100644 --- a/externals/grill/flext/readme.txt +++ b/externals/grill/flext/readme.txt @@ -33,7 +33,7 @@ Package files: - flmspbuffer.h: MaxMSP's inofficial buffer.h included here for conveniance > for PD you need the pd source code (which is most likely part of the distribution) -> for Max/MSP you will also need the Max/MSP SDK (and for threading the GUSI library) +> for Max/MSP you will also need the Max/MSP SDK (and for threading the Multiprocessing library) > if you choose to compile with SndObj support you will need the respective library > download from: http://www.may.ie/academic/music/musictec/SndObj/main.html @@ -44,7 +44,7 @@ The package should at least compile (and is tested) with the following compilers pd - Windows: ------------- -For any of these compilers define "PD" and "NT". +For any of these compilers define "FLEXT_SYS=2". o Microsoft Visual C++ 6: edit "config-pd-msvc.txt" & run "build-pd-msvc.bat" @@ -54,25 +54,27 @@ o Cygwin: edit "config-pd-cygwin.txt" & run "sh build-pd-cygwin.sh" pd - linux: ----------- -Be sure to define "PD". +Be sure to define "FLEXT_SYS=2". o GCC: edit "config-pd-linux.txt" & run "sh build-pd-linux.sh" pd - MacOSX: ----------- -Be sure to define "PD". +Be sure to define "FLEXT_SYS=2". o GCC: edit "config-pd-darwin.txt" & run "sh build-pd-darwin.sh" Max/MSP - MacOS 9: ------------------ -Be sure to define "MAXMSP". +Be sure to define "FLEXT_SYS=1" - alternatively use the prefix file "flcwmax.h" o Metrowerks CodeWarrior V6: edit & use the "flext.cw" project file Max/MSP - MacOSX: ------------------ -... sorry, not yet... would someone please donate me a CodeWarrior V8 ? +Be sure to define "FLEXT_SYS=1" - alternatively use the prefix file "flcwmax-x.h" or "flcwmax-x-thr.h" for threading support. + +o Metrowerks CodeWarrior V6: edit & use the "flext.cw" project file ---------------------------------------------------------------------------- @@ -98,6 +100,7 @@ see flext.h, fldefs.h and flclass.h for the documented base definitions and clas Version history: 0.4.1: +- full port for Max@OSX - fixed crash issue in flext_dsp when there are NO signal inlets or outlets defined (this is possibly only a problem for the signal2 tutorial example) - added flext::GetType(t_atom &), flext::ZeroMem @@ -115,6 +118,10 @@ Version history: - put more flext functions into flext static class - replaced ChangePriority by RefPriority - fixed setting of priorities... problems were caused by a compiler bug (MSVC 6) +- made a portable threading interface with support for threading libraries other than pthreads (FLEXT_THREADS defined as FLEXT_THR_*) +- implemented threading support with the MacOS MP thread library +- stripped the ThrMutex and ThrCond classes of non-portable (and irrelevant) functionality +- simplified "ToQueue*" and threaded "ToOut*" message queue mechanism for Max/MSP 0.4.0: - the use of the const keyword is enforced (e.g. the preferred type for symbols is now "const t_symbol *") diff --git a/externals/grill/flext/source/flbase.h b/externals/grill/flext/source/flbase.h index 0c8e8e7e..79128e53 100644 --- a/externals/grill/flext/source/flbase.h +++ b/externals/grill/flext/source/flbase.h @@ -20,7 +20,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "flstdc.h" #include "flsupport.h" -class flext_obj; +class FLEXT_EXT flext_obj; // ---------------------------------------------------------------------------- /*! \brief The obligatory PD or Max/MSP object header @@ -85,7 +85,7 @@ struct FLEXT_EXT flext_hdr */ // ---------------------------------------------------------------------------- -class flext_obj: +class FLEXT_EXT flext_obj: public flext { public: diff --git a/externals/grill/flext/source/flclass.h b/externals/grill/flext/source/flclass.h index dd51d85a..ab90667a 100644 --- a/externals/grill/flext/source/flclass.h +++ b/externals/grill/flext/source/flclass.h @@ -40,7 +40,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -class flext_base: +class FLEXT_EXT flext_base: public flext_obj { FLEXT_HEADER_S(flext_base,flext_obj,Setup) @@ -392,6 +392,12 @@ public: @{ */ + //! Start a thread for this object + bool StartThread(void (*meth)(thr_params *p),thr_params *p,const char *) { p->cl = this; return flext::LaunchThread(meth,p); } + + //! Terminate all threads of this object + bool StopThreads(); + //! Check if current thread should terminate bool ShouldExit() const; @@ -401,75 +407,6 @@ public: // xxx internal stuff xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -protected: - -// --- thread stuff ----------------------------------------------- - -#ifdef FLEXT_THREADS - - /*! \brief Thread parameters - \internal - */ - class thr_params: - public flext - { - public: - thr_params(flext_base *c,int n = 1); - ~thr_params(); - - void set_any(const t_symbol *s,int argc,const t_atom *argv); - void set_list(int argc,const t_atom *argv); - - flext_base *cl; - union _data { - bool _bool; - float _float; - int _int; - t_symptr _t_symptr; - struct { AtomAnything *args; } _any; - struct { AtomList *args; } _list; - struct { void *data; } _ext; - } *var; - }; - - /*! \brief This represents an entry to the list of active method threads - \internal - */ - class thr_entry - { - public: - thr_entry(flext_base *t,void *(*m)(thr_params *),thr_params *p,pthread_t id = pthread_self()); - - //! \brief Check if this class represents the current thread - bool Is(pthread_t id = pthread_self()) const { return pthread_equal(thrid,id) != 0; } - - flext_base *th; - void *(*meth)(thr_params *); - thr_params *params; - pthread_t thrid; - bool active,shouldexit; - thr_entry *nxt; - }; - - /*! \brief Add current thread to list of active threads - \return true on success - \internal - */ - bool PushThread(); - - /*! \brief Remove current thread from list of active threads - \internal - */ - void PopThread(); - -public: - /*! \brief Start a method thread - \internal - */ - bool StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname); - -#endif - protected: flext_base(); @@ -630,30 +567,18 @@ private: static bool cb_GetAttrib(flext_base *c,const t_symbol *s,int argc,const t_atom *argv) { return c->GetAttrib(s,argc,argv); } static bool cb_SetAttrib(flext_base *c,const t_symbol *s,int argc,const t_atom *argv) { return c->SetAttrib(s,argc,argv); } -#ifdef FLEXT_THREADS - ThrMutex qmutex; - - static thr_entry *thrhead,*thrtail; - static ThrMutex tlmutex; - - static pthread_t thrhelpid; - static bool StartHelper(); - static bool StopHelper(); - static void ThrHelper(void *); - void TermThreads(); -#endif + // queue stuff class qmsg; qmsg *qhead,*qtail; t_qelem *qclk; -#if FLEXT_SYS == FLEXT_SYS_MAX - t_clock *yclk; - static void YTick(flext_base *th); -#endif - static void QTick(flext_base *th); void Queue(qmsg *m); +#ifdef FLEXT_THREADS + ThrMutex qmutex; +#endif + #if FLEXT_SYS == FLEXT_SYS_PD // proxy object (for additional inlets) stuff diff --git a/externals/grill/flext/source/fldefs.h b/externals/grill/flext/source/fldefs.h index f7488fe0..353752f7 100644 --- a/externals/grill/flext/source/fldefs.h +++ b/externals/grill/flext/source/fldefs.h @@ -412,10 +412,10 @@ FLEXT_CALLBACK_1(M_FUN,t_symptr) //! Set up a threaded method callback with no arguments #define FLEXT_THREAD(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c) { \ - thr_params *p = new thr_params(c); \ + thr_params *p = new thr_params; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ delete p; \ @@ -423,16 +423,15 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(); \ th->PopThread(); \ } \ - return NULL; \ } //! Set up a threaded method callback for an anything argument #define FLEXT_THREAD_A(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,t_symbol *s,int argc,t_atom *argv) { \ - thr_params *p = new thr_params(c); p->set_any(s,argc,argv); \ + thr_params *p = new thr_params; p->set_any(s,argc,argv); \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ AtomAnything *args = p->var[0]._any.args; \ @@ -442,16 +441,15 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->PopThread(); \ } \ delete args; \ - return NULL; \ } //! Set up a threaded method callback for a variable argument list #define FLEXT_THREAD_V(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int argc,t_atom *argv) { \ - thr_params *p = new thr_params(c); p->set_list(argc,argv); \ + thr_params *p = new thr_params; p->set_list(argc,argv); \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ AtomList *args = p->var[0]._list.args; \ @@ -461,7 +459,6 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->PopThread(); \ } \ delete args; \ - return NULL; \ } /*! \brief Set up a threaded method callback for an arbitrary data struct @@ -469,10 +466,10 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ */ #define FLEXT_THREAD_X(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,void *data) { \ - thr_params *p = new thr_params(c); p->var[0]._ext.data = data; \ + thr_params *p = new thr_params; p->var[0]._ext.data = data; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ void *data = p->var[0]._ext.data; \ @@ -482,16 +479,15 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->PopThread(); \ } \ delete data; \ - return NULL; \ } //! Set up a threaded method callback for a boolean argument #define FLEXT_THREAD_B(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int &arg1) { \ - thr_params *p = new thr_params(c); p->var[0]._bool = arg1 != 0; \ + thr_params *p = new thr_params; p->var[0]._bool = arg1 != 0; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ bool b = p->var[0]._bool; \ @@ -500,17 +496,16 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(b); \ th->PopThread(); \ } \ - return NULL; \ } //! Set up a threaded method callback for 1 argument #define FLEXT_THREAD_1(M_FUN,TP1) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1) { \ - thr_params *p = new thr_params(c,1); \ + thr_params *p = new thr_params(1); \ p->var[0]._ ## TP1 = arg1; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ const TP1 v1 = p->var[0]._ ## TP1; \ @@ -519,18 +514,17 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(v1); \ th->PopThread(); \ } \ - return NULL; \ } //! Set up a threaded method callback for 2 arguments #define FLEXT_THREAD_2(M_FUN,TP1,TP2) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2) { \ - thr_params *p = new thr_params(c,2); \ + thr_params *p = new thr_params(2); \ p->var[0]._ ## TP1 = arg1; \ p->var[1]._ ## TP2 = arg2; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ const TP1 v1 = p->var[0]._ ## TP1; \ @@ -540,19 +534,18 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(v1,v2); \ th->PopThread(); \ } \ - return NULL; \ } //! Set up a threaded method callback for 3 arguments #define FLEXT_THREAD_3(M_FUN,TP1,TP2,TP3) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3) { \ - thr_params *p = new thr_params(c,3); \ + thr_params *p = new thr_params(3); \ p->var[0]._ ## TP1 = arg1; \ p->var[1]._ ## TP2 = arg2; \ p->var[2]._ ## TP3 = arg3; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ const TP1 v1 = p->var[0]._ ## TP1; \ @@ -563,20 +556,19 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(v1,v2,v3); \ th->PopThread(); \ } \ - return NULL; \ } //! Set up a threaded method callback for 4 arguments #define FLEXT_THREAD_4(M_FUN,TP1,TP2,TP3,TP4) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP4 &arg4) { \ - thr_params *p = new thr_params(c,4); \ + thr_params *p = new thr_params(4); \ p->var[0]._ ## TP1 = arg1; \ p->var[1]._ ## TP2 = arg2; \ p->var[2]._ ## TP3 = arg3; \ p->var[3]._ ## TP4 = arg4; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ const TP1 v1 = p->var[0]._ ## TP1; \ @@ -588,13 +580,12 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(v1,v2,v3,v4); \ th->PopThread(); \ } \ - return NULL; \ } //! Set up a threaded method callback for 5 arguments #define FLEXT_THREAD_5(M_FUN,TP1,TP2,TP3,TP4,TP5) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP4 &arg4,TP5 &arg5) { \ - thr_params *p = new thr_params(c,5); \ + thr_params *p = new thr_params(5); \ p->var[0]._ ## TP1 = arg1; \ p->var[1]._ ## TP2 = arg2; \ p->var[2]._ ## TP3 = arg3; \ @@ -602,7 +593,7 @@ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP p->var[4]._ ## TP5 = arg5; \ return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ -static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ +static void FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST(p->cl); \ bool ok = th->PushThread(); \ const TP1 v1 = p->var[0]._ ## TP1; \ @@ -615,7 +606,6 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ th->M_FUN(v1,v2,v3,v4,v5); \ th->PopThread(); \ } \ - return NULL; \ } diff --git a/externals/grill/flext/source/fldsp.h b/externals/grill/flext/source/fldsp.h index b1fbe23d..4926d873 100644 --- a/externals/grill/flext/source/fldsp.h +++ b/externals/grill/flext/source/fldsp.h @@ -24,7 +24,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. /*! \brief Flext dsp enabled base object */ -class flext_dsp: +class FLEXT_EXT flext_dsp: public flext_base { FLEXT_HEADER_S(flext_dsp,flext_base,Setup) diff --git a/externals/grill/flext/source/flext.cpp b/externals/grill/flext/source/flext.cpp index e052e56a..f74d11c6 100644 --- a/externals/grill/flext/source/flext.cpp +++ b/externals/grill/flext/source/flext.cpp @@ -130,15 +130,8 @@ flext_base::flext_base(): { LOG1("%s - flext logging is on",thisName()); -#ifdef FLEXT_THREADS -// shouldexit = false; -// thrhead = thrtail = NULL; -#endif qhead = qtail = NULL; qclk = (t_qelem *)(qelem_new(this,(t_method)QTick)); -#if FLEXT_SYS == FLEXT_SYS_MAX - yclk = (t_clock *)(clock_new(this,(t_method)YTick)); -#endif AddMethod(0,"getattributes",(methfun)cb_ListAttrib); } @@ -146,15 +139,12 @@ flext_base::flext_base(): flext_base::~flext_base() { #ifdef FLEXT_THREADS - TermThreads(); + StopThreads(); #endif // send remaining pending messages while(qhead) QTick(this); qelem_free((t_qelem *)qclk); -#if FLEXT_SYS == FLEXT_SYS_MAX - clock_free((object *)yclk); -#endif if(inlist) delete inlist; if(outlist) delete outlist; @@ -464,7 +454,7 @@ void flext_base::Setup(t_class *c) ADD_IN_FT(9); #ifdef FLEXT_THREADS - thrid = pthread_self(); + thrid = GetThreadId(); StartHelper(); #endif diff --git a/externals/grill/flext/source/flext.h b/externals/grill/flext/source/flext.h index 1e72daa5..9b5da4e6 100644 --- a/externals/grill/flext/source/flext.h +++ b/externals/grill/flext/source/flext.h @@ -34,11 +34,20 @@ WARRANTIES, see the file, "license.txt," in this distribution. // determine System/OS/CPU #include "flprefix.h" +// include headers necessary for multi-threading #ifdef FLEXT_THREADS -extern "C" { - #include - #include -} + #if FLEXT_THREADS == FLEXT_THR_POSIX + extern "C" { + #include + #include + } + #elif FLEXT_THREADS == FLEXT_THR_MP + #include + #elif FLEXT_THREADS == FLEXT_THR_WIN32 + #include + #else + #error "Thread model not supported" + #endif #endif // include all the flext interface definitions diff --git a/externals/grill/flext/source/flout.cpp b/externals/grill/flext/source/flout.cpp index 16a6ea29..9dbda7f1 100644 --- a/externals/grill/flext/source/flout.cpp +++ b/externals/grill/flext/source/flout.cpp @@ -67,8 +67,6 @@ public: struct { int argc; t_atom *argv; } _list; struct { const t_symbol *s; int argc; t_atom *argv; } _any; }; - -// void Add(qmsg *o); }; flext_base::qmsg::~qmsg() @@ -84,44 +82,24 @@ void flext_base::qmsg::Clear() tp = tp_none; } -/* -void flext_base::qmsg::Add(qmsg *o) -{ - if(nxt) nxt->Add(o); - else nxt = o; -} -*/ - -#if FLEXT_SYS == FLEXT_SYS_MAX -void flext_base::YTick(flext_base *th) -{ - clock_delay(th->yclk,0); - qelem_set(th->qclk); -#ifdef FLEXT_THREADS - sched_yield(); -#endif -} -#endif - void flext_base::QTick(flext_base *th) { -#ifdef FLEXT_THREADS - -#ifdef FLEXT_DEBUG +// post("qtick"); +#if defined(FLEXT_THREADS) && defined(FLEXT_DEBUG) if(!th->IsSystemThread()) { error("flext - Queue tick called by wrong thread!"); return; } #endif +#ifdef FLEXT_THREADS th->qmutex.Lock(); #endif - while(th->qhead) { + for(;;) { qmsg *m = th->qhead; + if(!m) break; -#if FLEXT_SYS == FLEXT_SYS_MAX - short state = lockout_set(1); -#endif + CRITON(); switch(m->tp) { case qmsg::tp_bang: th->ToOutBang(m->out); break; @@ -135,9 +113,7 @@ void flext_base::QTick(flext_base *th) #endif } -#if FLEXT_SYS == FLEXT_SYS_MAX - lockout_set(state); -#endif + CRITOFF(); th->qhead = m->nxt; if(!th->qhead) th->qtail = NULL; @@ -151,23 +127,26 @@ void flext_base::QTick(flext_base *th) void flext_base::Queue(qmsg *m) { +// post("Queue"); + #ifdef FLEXT_THREADS qmutex.Lock(); #endif if(qtail) qtail->nxt = m; else qhead = m; qtail = m; +#ifdef FLEXT_THREADS + qmutex.Unlock(); +#endif + #if FLEXT_SYS == FLEXT_SYS_PD clock_delay(qclk,0); #elif FLEXT_SYS == FLEXT_SYS_MAX - clock_delay(yclk,0); + qelem_set(qclk); #else #error #endif -#ifdef FLEXT_THREADS - qmutex.Unlock(); -#endif } void flext_base::ToQueueBang(outlet *o) const diff --git a/externals/grill/flext/source/flprefix.h b/externals/grill/flext/source/flprefix.h index d2c7f173..6aa1e0ac 100755 --- a/externals/grill/flext/source/flprefix.h +++ b/externals/grill/flext/source/flprefix.h @@ -50,6 +50,11 @@ WARRANTIES, see the file, "license.txt," in this distribution. #define FLEXT_CPU_MIPS 3 #define FLEXT_CPU_ALPHA 4 +// --- definitions for FLEXT_THREADS ----------------- +#define FLEXT_THR_POSIX 1 // pthreads +#define FLEXT_THR_WIN32 2 // Win32 native +#define FLEXT_THR_MP 3 // MacOS MPThreads + // --------------------------------------------------- // support old definitions @@ -233,4 +238,15 @@ WARRANTIES, see the file, "license.txt," in this distribution. // #pragma message("Compiling for PD") #endif +// set threading model +#ifdef FLEXT_THREADS + #undef FLEXT_THREADS + #if FLEXT_OS == FLEXT_OS_MACOS && FLEXT_SYS == FLEXT_SYS_MAX + // Max crashes with posix threads (but don't know why...) + #define FLEXT_THREADS FLEXT_THR_MP + #else + #define FLEXT_THREADS FLEXT_THR_POSIX + #endif +#endif + #endif diff --git a/externals/grill/flext/source/flsupport.h b/externals/grill/flext/source/flsupport.h index 9429599d..ad7158f9 100644 --- a/externals/grill/flext/source/flsupport.h +++ b/externals/grill/flext/source/flsupport.h @@ -17,6 +17,8 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "flstdc.h" +class FLEXT_EXT flext_base; + class FLEXT_EXT flext { /*! \defgroup FLEXT_SUPPORT Flext support class @@ -392,29 +394,129 @@ public: */ //! thread type +#if FLEXT_THREADS == FLEXT_THR_MP + typedef MPTaskID thrid_t; +#elif FLEXT_THREADS == FLEXT_THR_POSIX typedef pthread_t thrid_t; +#else +#error +#endif + + /*! \brief Get current thread id + */ + static thrid_t GetThreadId() { +#if FLEXT_THREADS == FLEXT_THR_POSIX + return pthread_self(); +#elif FLEXT_THREADS == FLEXT_THR_MP + return MPCurrentTaskID(); +#else +#error +#endif + } + + /*! \brief Get system thread id + */ + static thrid_t GetSysThreadId() { return thrid; } + + //! Check if current thread is the realtime system's thread + static bool IsThread(thrid_t t,thrid_t ref = GetThreadId()) { +#if FLEXT_THREADS == FLEXT_THR_POSIX + return pthread_equal(ref,t) != 0; +#else + return ref == t; +#endif + } + + //! Check if current thread is the realtime system's thread + static bool IsSystemThread() { return IsThread(GetSysThreadId()); } + + + /*! \brief Thread parameters + \internal + */ + class thr_params + { + public: + thr_params(int n = 1); + ~thr_params(); + + void set_any(const t_symbol *s,int argc,const t_atom *argv); + void set_list(int argc,const t_atom *argv); + + flext_base *cl; + union _data { + bool _bool; + float _float; + int _int; + t_symptr _t_symptr; + struct { AtomAnything *args; } _any; + struct { AtomList *args; } _list; + struct { void *data; } _ext; + } *var; + }; + + /*! \brief This represents an entry to the list of active method threads + \internal + */ + class thr_entry + { + public: + thr_entry(void (*m)(thr_params *),thr_params *p,thrid_t id = GetThreadId()); + + //! \brief Check if this class represents the current thread + bool Is(thrid_t id = GetThreadId()) const { return IsThread(thrid,id); } + + flext_base *This() const { return th; } + thrid_t Id() const { return thrid; } + + flext_base *th; + void (*meth)(thr_params *); + thr_params *params; + thrid_t thrid; + bool active,shouldexit; +#if FLEXT_THREADS == FLEXT_THR_MP + int weight; +#endif + thr_entry *nxt; + }; protected: + + static thrid_t thrhelpid; + static bool StartHelper(); + static bool StopHelper(); + static void ThrHelper(void *); + //! system's thread id static thrid_t thrid; // the system thread public: - //! Check if current thread is the realtime system's thread - static bool IsSystemThread() { pthread_t cur = pthread_self(); return pthread_equal(cur,thrid) != 0; } - /*! \brief Yield to other threads \remark A call to this is only needed for systems with cooperative multitasking like MacOS<=9 */ - static void ThrYield() { sched_yield(); } - - /*! \brief Get current thread id - */ - static thrid_t GetThreadId() { return pthread_self(); } + static void ThrYield() { +#if FLEXT_THREADS == FLEXT_THR_POSIX + sched_yield(); +#elif FLEXT_THREADS == FLEXT_THR_MP + MPYield(); +#else +#error +#endif + } - /*! \brief Get current thread id + /*! \brief Query whether task is preemptive */ - static thrid_t GetSysThreadId() { return thrid; } + static bool IsThreadPreemptive(thrid_t t = GetThreadId()) { +#if FLEXT_THREADS == FLEXT_THR_POSIX || FLEXT_THREADS == FLEXT_THR_WIN32 + return true; +#elif FLEXT_THREADS == FLEXT_THR_MP + return MPTaskIsPreemptive(t); +#else +#error +#endif + } + /*! \brief Increase/Decrease priority of a thread */ @@ -431,35 +533,63 @@ public: /*! \brief Thread mutex \sa pthreads documentation */ - class ThrMutex + class FLEXT_EXT ThrMutex +#if FLEXT_THREADS == FLEXT_THR_POSIX { public: //! Construct thread mutex - ThrMutex(): cnt(0) { pthread_mutex_init(&mutex,NULL); } + ThrMutex() /*: cnt(0)*/ { pthread_mutex_init(&mutex,NULL); } //! Destroy thread mutex ~ThrMutex() { pthread_mutex_destroy(&mutex); } //! Lock thread mutex - int Lock() { cnt = 1; return pthread_mutex_lock(&mutex); } + bool Lock() { /*cnt = 1;*/ return pthread_mutex_lock(&mutex) == 0; } + //! Lock thread mutex + bool WaitForLock(float tm) { /*cnt = 1;*/ return pthread_mutex_lock(&mutex) == 0; } //! Try to lock, but don't wait - int TryLock() { return pthread_mutex_trylock(&mutex); } + bool TryLock() { return pthread_mutex_trylock(&mutex) == 0; } //! Unlock thread mutex - int Unlock() { cnt = 0; return pthread_mutex_unlock(&mutex); } - + bool Unlock() { /*cnt = 0;*/ return pthread_mutex_unlock(&mutex) == 0; } +/* //! Lock thread mutex (increase lock count by one) void Push() { if(!cnt++) Lock(); } //! Unlock thread mutex if lock count reaches zero void Pop() { if(!--cnt) Unlock(); } +*/ protected: pthread_mutex_t mutex; - int cnt; +// int cnt; }; +#elif FLEXT_THREADS == FLEXT_THR_MP + { + public: + //! Construct thread mutex + ThrMutex() /*: cnt(0)*/ { MPCreateCriticalRegion(&crit); } + //! Destroy thread mutex + ~ThrMutex() { MPDeleteCriticalRegion(crit); } + + //! Lock thread mutex + bool Lock() { /*cnt = 1;*/ return MPEnterCriticalRegion(crit,kDurationForever) == noErr; } + //! Wait to lock thread mutex + bool WaitForLock(float tm) { /*cnt = 1;*/ return MPEnterCriticalRegion(crit,tm*kDurationMicrosecond*1.e6) == noErr; } + //! Try to lock, but don't wait + bool TryLock() { return MPEnterCriticalRegion(crit,kDurationImmediate) == noErr; } + //! Unlock thread mutex + bool Unlock() { /*cnt = 0;*/ return MPExitCriticalRegion(crit) == noErr; } + + protected: + MPCriticalRegionID crit; + }; +#else +#error "Not implemented" +#endif /*! \brief Thread conditional \sa pthreads documentation */ - class ThrCond: - public ThrMutex + class FLEXT_EXT ThrCond +#if FLEXT_THREADS == FLEXT_THR_POSIX + :public ThrMutex { public: //! Construct thread conditional @@ -468,24 +598,81 @@ public: ~ThrCond() { pthread_cond_destroy(&cond); } //! Wait for condition - int Wait() { return pthread_cond_wait(&cond,&mutex); } + bool Wait() { + Lock(); + bool ret = pthread_cond_wait(&cond,&mutex) == 0; + Unlock(); + return ret; + } /*! \brief Wait for condition (for a certain time) \param time Wait time in seconds */ - int TimedWait(float time) + bool TimedWait(float time) { timespec tm; tm.tv_sec = (long)time; tm.tv_nsec = (long)((time-(long)time)*1.e9); - return pthread_cond_timedwait(&cond,&mutex,&tm); + Lock(); + bool ret = pthread_cond_timedwait(&cond,&mutex,&tm) == 0; + Unlock(); + return ret; } //! Signal condition - int Signal() { return pthread_cond_signal(&cond); } + bool Signal() + { + Lock(); + bool ret = pthread_cond_signal(&cond) == 0; + Unlock(); + return ret; + } //! Broadcast condition - int Broadcast() { return pthread_cond_broadcast(&cond); } +// int Broadcast() { return pthread_cond_broadcast(&cond); } protected: pthread_cond_t cond; }; +#elif FLEXT_THREADS == FLEXT_THR_MP + { + public: + //! Construct thread conditional + ThrCond() { MPCreateEvent(&ev); } + //! Destroy thread conditional + ~ThrCond() { MPDeleteEvent(ev); } + + //! Wait for condition + bool Wait() { return MPWaitForEvent(ev,NULL,kDurationForever) == noErr; } + + /*! \brief Wait for condition (for a certain time) + \param time Wait time in seconds + */ + bool TimedWait(float tm) { return MPWaitForEvent(ev,NULL,tm*kDurationMicrosecond*1.e6) == noErr; } + + //! Signal condition + bool Signal() { return MPSetEvent(ev,1) == noErr; } // one bit needs to be set at least + //! Broadcast condition +// int Broadcast() { return pthread_cond_broadcast(&cond); } + protected: + MPEventID ev; + }; +#else +#error "Not implemented" +#endif + + /*! \brief Add current thread to list of active threads + \return true on success + \internal + */ + static bool PushThread(); + + /*! \brief Remove current thread from list of active threads + \internal + */ + static void PopThread(); + + /*! \brief Launch a thread + \remark thr_params *p may be NULL if not needed + */ + static bool LaunchThread(void (*meth)(thr_params *p),thr_params *p); + //! @} FLEXT_S_THREAD #endif // FLEXT_THREADS diff --git a/externals/grill/flext/source/flthr.cpp b/externals/grill/flext/source/flthr.cpp index 96e52b0d..e8834b76 100644 --- a/externals/grill/flext/source/flthr.cpp +++ b/externals/grill/flext/source/flthr.cpp @@ -17,57 +17,60 @@ WARRANTIES, see the file, "license.txt," in this distribution. #ifdef FLEXT_THREADS -#if FLEXT_OS == FLEXT_OS_WIN -#include -#endif - #include //! Thread id of system thread flext::thrid_t flext::thrid; //! Thread id of helper thread -flext::thrid_t flext_base::thrhelpid; +flext::thrid_t flext::thrhelpid; -flext_base::thr_entry *flext_base::thrhead = NULL,*flext_base::thrtail = NULL; -flext::ThrMutex flext_base::tlmutex; +/* +flext::thr_entry *flext::thrhead = NULL,*flext::thrtail = NULL; +flext::ThrMutex flext::tlmutex; +*/ +static flext::thr_entry *thrhead = NULL,*thrtail = NULL; +static flext::ThrMutex tlmutex; //! Helper thread should terminate -bool thrhelpexit = false; +static bool thrhelpexit = false; //! Helper thread conditional -flext::ThrCond *thrhelpcond = NULL; - - -flext_base::thr_entry::thr_entry(flext_base *t,void *(*m)(thr_params *),thr_params *p,pthread_t id): - th(t),meth(m),params(p),thrid(id), - active(false),shouldexit(false), - nxt(NULL) -{} +static flext::ThrCond *thrhelpcond = NULL; //! Start helper thread -bool flext_base::StartHelper() +bool flext::StartHelper() { + bool ok = false; +#if FLEXT_THREADS == FLEXT_THR_POSIX pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); thrhelpexit = false; int ret = pthread_create (&thrhelpid,&attr,(void *(*)(void *))ThrHelper,NULL); - if(ret) { - error((char *)("flext - Could not launch helper thread!")); - return false; + ok = !ret; +#elif FLEXT_THREADS == FLEXT_THR_MP + if(!MPLibraryIsLoaded()) + error("Thread library is not loaded"); + else { + OSStatus ret = MPCreateTask((TaskProc)ThrHelper,NULL,0,0,0,0,0,&thrhelpid); + ok = ret == noErr; } - else - return true; +#else +#error +#endif + if(!ok) + error("flext - Could not launch helper thread!"); + return ok; } #if 0 /*! \brief Stop helper thread \note not called! */ -bool flext_base::StopHelper() +bool flext::StopHelper() { thrhelpexit = true; if(thrhelpcond) thrhelpcond->Signal(); @@ -75,12 +78,16 @@ bool flext_base::StopHelper() #endif //! Static helper thread function -void flext_base::ThrHelper(void *) +void flext::ThrHelper(void *) { +#if FLEXT_THREADS == FLEXT_THR_POSIX // set prototype thread attributes pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); +#endif + +// post("Helper"); // set thread priority one point below normal // so thread construction won't disturb real-time audio @@ -90,18 +97,32 @@ void flext_base::ThrHelper(void *) // helper loop for(;;) { +// post("Helper loop"); + thrhelpcond->Wait(); if(thrhelpexit) break; +// post("Helper signalled"); tlmutex.Lock(); +// post("Helper after lock"); + // start all inactive threads in queue thr_entry *prv = NULL,*ti; for(ti = thrhead; ti; prv = ti,ti = ti->nxt) { if(!ti->active) { - int ret = pthread_create (&ti->thrid,&attr,(void *(*)(void *))ti->meth,ti->params); - if(ret) { - error((char *)("flext - Could not launch thread!")); + bool ok; + +// post("Helper start thread"); +#if FLEXT_THREADS == FLEXT_THR_POSIX + ok = pthread_create (&ti->thrid,&attr,(void *(*)(void *))ti->meth,ti->params) == 0; +#elif FLEXT_THREADS == FLEXT_THR_MP + ok = MPCreateTask((TaskProc)ti->meth,ti->params,0,0,0,0,0,&ti->thrid) == noErr; +#else +#error +#endif + if(!ok) { + error("flext - Could not launch thread!"); // delete from queue if(prv) @@ -114,6 +135,8 @@ void flext_base::ThrHelper(void *) delete ti; } else { +// post("Helper thread ok"); + // set active flag ti->active = true; } @@ -128,47 +151,56 @@ void flext_base::ThrHelper(void *) } -bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname) +bool flext::LaunchThread(void (*meth)(thr_params *p),thr_params *p) { #ifdef FLEXT_DEBUG - if(!p || !thrhelpcond) { + if(!thrhelpcond) { ERRINTERNAL(); return false; } #endif +// post("make threads"); + tlmutex.Lock(); // make an entry into thread list - thr_entry *nt = new thr_entry(this,meth,p); + thr_entry *nt = new thr_entry(meth,p); if(thrtail) thrtail->nxt = nt; else thrhead = nt; thrtail = nt; + tlmutex.Unlock(); + +// post("signal helper"); + // signal thread helper thrhelpcond->Signal(); - tlmutex.Unlock(); return true; } bool flext_base::ShouldExit() const { + bool ret = true; + + tlmutex.Lock(); for(thr_entry *ti = thrhead; ti; ti = ti->nxt) - if(ti->Is()) return ti->shouldexit; + if(ti->Is()) { ret = ti->shouldexit; break; } + tlmutex.Unlock(); // thread was not found -> EXIT!!! - return true; + return ret; } -bool flext_base::PushThread() +bool flext::PushThread() { // set priority of newly created thread one point below the system thread's RelPriority(-1); return true; } -void flext_base::PopThread() +void flext::PopThread() { tlmutex.Lock(); @@ -190,7 +222,7 @@ void flext_base::PopThread() } else { #ifdef FLEXT_DEBUG - post("%s - INTERNAL ERROR: Thread not found!",thisName()); + post("flext - INTERNAL ERROR: Thread not found!"); #endif } @@ -198,46 +230,70 @@ void flext_base::PopThread() } //! Terminate all object threads -void flext_base::TermThreads() +bool flext_base::StopThreads() { thr_entry *t; // signal termination - for(t = thrhead; t; t = t->nxt) - if(t->th == this) t->shouldexit = true; + tlmutex.Lock(); + for(t = thrhead; t; t = t->nxt) { + if(t->This() == this) t->shouldexit = true; + } + tlmutex.Unlock(); - // TODO: maybe there should be a thread conditional for every thread so that it can be signaled + // TODO: maybe there should be a thread conditional for every thread so that it can be signalled efficiently - // wait for thread termination + // wait for thread termination (1 second max.) + int cnt; for(int wi = 0; wi < 100; ++wi) { - int cnt = 0; + cnt = 0; + tlmutex.Lock(); for(t = thrhead; t; t = t->nxt) - if(t->th == this) ++cnt; + if(t->This() == this) ++cnt; + tlmutex.Unlock(); if(!cnt) break; Sleep(0.01f); } - // --- all object threads have terminated by now ------- + if(cnt) { +#ifdef FLEXT_DEBUG + post("flext - doing hard thread termination"); +#endif + + // --- all object threads have terminated by now ------- - qmutex.Lock(); // Lock message queue - tlmutex.Lock(); + qmutex.Lock(); // Lock message queue + tlmutex.Lock(); - // timeout -> hard termination - for(t = thrhead; t; ) - if(t->th == this) { - if(pthread_cancel(t->thrid)) post("%s - Thread could not be terminated!",thisName()); - thr_entry *tn = t->nxt; - t->nxt = NULL; delete t; - t = tn; - } - else t = t->nxt; + // timeout -> hard termination + for(t = thrhead; t; ) + if(t->This() == this) { + #if FLEXT_THREADS == FLEXT_THR_POSIX + if(pthread_cancel(t->thrid)) post("%s - Thread could not be terminated!",thisName()); + #elif FLEXT_THREADS == FLEXT_THR_MP + MPTerminateTask(t->thrid,0); + // here, we should use a task queue to check whether the task has really terminated!! + #else + #error + #endif + thr_entry *tn = t->nxt; + t->nxt = NULL; delete t; + t = tn; + } + else t = t->nxt; - tlmutex.Unlock(); - qmutex.Unlock(); + tlmutex.Unlock(); + qmutex.Unlock(); + } + +// post("All threads have terminated"); + + return true; } bool flext::RelPriority(int dp,thrid_t ref,thrid_t id) { +#if FLEXT_THREADS == FLEXT_THR_POSIX sched_param parm; int policy; if(pthread_getschedparam(ref,&policy,&parm) < 0) { @@ -274,11 +330,39 @@ bool flext::RelPriority(int dp,thrid_t ref,thrid_t id) } } return true; +#elif FLEXT_THREADS == FLEXT_THR_MP + thr_entry *t; + for(t = thrhead; t && t->Id() != id; t = t->nxt) {} + if(t) { + // thread found in list + int w = GetPriority(id); + if(dp < 0) w /= 1<<(-dp); + else w *= 1< 10000) { + #ifdef FLEXT_DEBUG + post("flext - maximum thread priority reached"); + #endif + w = 10000; + } + t->weight = w; + return MPSetTaskWeight(id,w) == noErr; + } + else return false; +#else +#error +#endif } int flext::GetPriority(thrid_t id) { +#if FLEXT_THREADS == FLEXT_THR_POSIX sched_param parm; int policy; if(pthread_getschedparam(id,&policy,&parm) < 0) { @@ -288,11 +372,19 @@ int flext::GetPriority(thrid_t id) return -1; } return parm.sched_priority; +#elif FLEXT_THREADS == FLEXT_THR_MP + thr_entry *t; + for(t = thrhead; t && t->Id() != id; t = t->nxt) {} + return t?t->weight:-1; +#else +#error +#endif } bool flext::SetPriority(int p,thrid_t id) { +#if FLEXT_THREADS == FLEXT_THR_POSIX sched_param parm; int policy; if(pthread_getschedparam(id,&policy,&parm) < 0) { @@ -311,12 +403,34 @@ bool flext::SetPriority(int p,thrid_t id) } } return true; +#elif FLEXT_THREADS == FLEXT_THR_MP + thr_entry *t; + for(t = thrhead; t && t->Id() != id; t = t->nxt) {} + if(t) + return MPSetTaskWeight(id,t->weight = p) == noErr; + else + return false; +#else +#error +#endif } -flext_base::thr_params::thr_params(flext_base *c,int n): cl(c),var(new _data[n]) {} + +flext_base::thr_params::thr_params(int n): cl(NULL),var(new _data[n]) {} flext_base::thr_params::~thr_params() { if(var) delete[] var; } void flext_base::thr_params::set_any(const t_symbol *s,int argc,const t_atom *argv) { var[0]._any.args = new AtomAnything(s,argc,argv); } void flext_base::thr_params::set_list(int argc,const t_atom *argv) { var[0]._list.args = new AtomList(argc,argv); } + +flext_base::thr_entry::thr_entry(void (*m)(thr_params *),thr_params *p,thrid_t id): + th(p?p->cl:NULL),meth(m),params(p),thrid(id), + active(false),shouldexit(false), +#if FLEXT_THREADS == FLEXT_THR_MP + weight(100), // MP default weight +#endif + nxt(NULL) +{} + + #endif // FLEXT_THREADS diff --git a/externals/grill/flext/tutorial/maxmsp/ex-thread1 b/externals/grill/flext/tutorial/maxmsp/ex-thread1 new file mode 100755 index 00000000..cd204b4a Binary files /dev/null and b/externals/grill/flext/tutorial/maxmsp/ex-thread1 differ diff --git a/externals/grill/flext/tutorial/maxmsp/ex-thread2 b/externals/grill/flext/tutorial/maxmsp/ex-thread2 new file mode 100755 index 00000000..d68690c4 Binary files /dev/null and b/externals/grill/flext/tutorial/maxmsp/ex-thread2 differ diff --git a/externals/grill/flext/tutorial/pd/ex-thread1.pd b/externals/grill/flext/tutorial/pd/ex-thread1.pd index 67d673db..341bcc37 100644 --- a/externals/grill/flext/tutorial/pd/ex-thread1.pd +++ b/externals/grill/flext/tutorial/pd/ex-thread1.pd @@ -1,43 +1,43 @@ -#N canvas 105 266 700 343 12; -#X obj 39 91 bng 25 250 50 0 empty empty start 0 -6 32 8 -261681 -1 --1; -#X obj 39 244 thread1; -#X obj 130 246 thread1; -#X obj 220 247 thread1; -#X obj 312 247 thread1; -#X obj 405 247 thread1; -#X obj 131 185 delay 200; -#X obj 220 184 delay 200; -#X obj 313 186 delay 200; -#X obj 404 185 delay 200; -#X text 78 85 click to start; -#X text 126 103 (if you click twice \, the same thread is started a -second time); -#X obj 16 8 cnv 15 550 40 empty empty thread1 10 22 32 24 -260818 -1 -0; -#X text 175 8 flext tutorial \, (C)2002 Thomas Grill; -#X text 175 28 http://www.parasitaere-kapazitaeten.net; -#X obj 39 277 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 12 --228992 -1 -1 0 256; -#X obj 131 277 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 -12 -228992 -1 -1 0 256; -#X obj 221 277 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 -12 -228992 -1 -1 0 256; -#X obj 311 277 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 -12 -228992 -1 -1 0 256; -#X obj 406 276 nbx 5 16 -1e+37 1e+37 0 0 empty empty empty 0 -6 32 -12 -228992 -1 -1 0 256; -#X connect 0 0 1 0; -#X connect 0 0 6 0; -#X connect 1 0 15 0; -#X connect 2 0 16 0; -#X connect 3 0 17 0; -#X connect 4 0 18 0; -#X connect 5 0 19 0; -#X connect 6 0 2 0; -#X connect 6 0 7 0; -#X connect 7 0 3 0; -#X connect 7 0 8 0; -#X connect 8 0 4 0; -#X connect 8 0 9 0; -#X connect 9 0 5 0; +#N canvas 105 266 702 345 12; +#X obj 39 91 bng 25 250 50 0 empty empty start 0 -6 0 8 -261681 -1 +-1; +#X obj 130 246 thread1; +#X obj 220 247 thread1; +#X obj 312 247 thread1; +#X obj 405 247 thread1; +#X obj 131 185 delay 200; +#X obj 220 184 delay 200; +#X obj 313 186 delay 200; +#X obj 404 185 delay 200; +#X text 78 85 click to start; +#X text 126 103 (if you click twice \, the same thread is started a +second time); +#X obj 16 8 cnv 15 550 40 empty empty thread1 10 22 0 24 -260818 -1 +0; +#X text 175 8 flext tutorial \, (C)2002 Thomas Grill; +#X text 175 28 http://www.parasitaere-kapazitaeten.net; +#X obj 131 277 nbx 5 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0 +12 -228992 -1 -1 0 256; +#X obj 221 277 nbx 5 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0 +12 -228992 -1 -1 0 256; +#X obj 311 277 nbx 5 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0 +12 -228992 -1 -1 0 256; +#X obj 406 276 nbx 5 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0 +12 -228992 -1 -1 0 256; +#X obj 39 244 thread1; +#X obj 39 277 nbx 5 16 -1e+037 1e+037 0 0 empty empty empty 0 -6 0 +12 -228992 -1 -1 0 256; +#X connect 0 0 5 0; +#X connect 0 0 18 0; +#X connect 1 0 14 0; +#X connect 2 0 15 0; +#X connect 3 0 16 0; +#X connect 4 0 17 0; +#X connect 5 0 1 0; +#X connect 5 0 6 0; +#X connect 6 0 2 0; +#X connect 6 0 7 0; +#X connect 7 0 3 0; +#X connect 7 0 8 0; +#X connect 8 0 4 0; +#X connect 18 0 19 0; diff --git a/externals/grill/flext/tutorial/readme.txt b/externals/grill/flext/tutorial/readme.txt index fa86a5ce..3e7004a1 100644 --- a/externals/grill/flext/tutorial/readme.txt +++ b/externals/grill/flext/tutorial/readme.txt @@ -39,7 +39,7 @@ o Metrowerks CodeWarrior V6: edit & use the several ".cw" project files Max/MSP - MacOSX: ------------------ -... sorry, not yet... would someone please donate me a CodeWarrior V8 ? +o Metrowerks CodeWarrior V6: edit & use the several ".cw" project files ---------------------------------------------------------------------------- diff --git a/externals/grill/flext/tutorial/thread1/main.cpp b/externals/grill/flext/tutorial/thread1/main.cpp index 72fb1019..f5e2a651 100644 --- a/externals/grill/flext/tutorial/thread1/main.cpp +++ b/externals/grill/flext/tutorial/thread1/main.cpp @@ -37,7 +37,7 @@ protected: void m_start(); // method function private: - // define threaded callback for method m_start (with boolean argument) + // define threaded callback for method m_start // the same syntax as with FLEXT_CALLBACK is used here FLEXT_THREAD(m_start); }; @@ -64,17 +64,19 @@ void thread1::m_start() for(int i = 0; i < 20 && !ShouldExit(); ++i) { ToOutInt(0,i); // output loop count +// post("%i",i); // wait for half a second for(int j = 0; j < 5 && !ShouldExit(); ++j) Sleep(0.1f); // note: we shall not block a thread for a longer time. // The system might want to destroy the object in the meantime and - // expects thread termination. - // Flext waits for 1 second by default, then it aborts the thread brutally + // expects thread termination. In such a case flext waits + // for 1 second by default, then it aborts the thread brutally } // output a final zero ToOutInt(0,0); +// post("end"); } diff --git a/externals/grill/flext/tutorial/thread1/thread1.cw b/externals/grill/flext/tutorial/thread1/thread1.cw index f971d4a3..680bdfba 100644 Binary files a/externals/grill/flext/tutorial/thread1/thread1.cw and b/externals/grill/flext/tutorial/thread1/thread1.cw differ diff --git a/externals/grill/flext/tutorial/thread2/main.cpp b/externals/grill/flext/tutorial/thread2/main.cpp index bd6354a2..2cdc37c3 100644 --- a/externals/grill/flext/tutorial/thread2/main.cpp +++ b/externals/grill/flext/tutorial/thread2/main.cpp @@ -88,18 +88,18 @@ void thread2::m_start(int st) ToOutInt(0,count); // output loop count } - cond.Lock(); // lock conditional running = false; // change state flag - cond.Signal(); // signal changed flag to watiting "stop" method - cond.Unlock(); // unlock conditional +// cond.Lock(); // lock conditional + cond.Signal(); // signal changed flag to waiting "stop" method +// cond.Unlock(); // unlock conditional } void thread2::m_stop() { - cond.Lock(); // lock conditional +// cond.Lock(); // lock conditional stopit = true; // set termination flag - while(*(&running) || *(&blipping)) // workaround for CodeWarrior! + while(*(&running) || *(&blipping)) // workaround for CodeWarrior (doesn't honor volatile modifier!) { cond.Wait(); // wait for signal by running threads } @@ -107,7 +107,7 @@ void thread2::m_stop() // --- Here, the threads should have stopped --- stopit = false; // reset flag - cond.Unlock(); // unlock conditional +// cond.Unlock(); // unlock conditional } @@ -126,9 +126,9 @@ void thread2::m_textout() Sleep(1.f); } - cond.Lock(); // lock conditional blipping = false; // change state flag - cond.Signal(); // signal changed flag to watiting "stop" method - cond.Unlock(); // unlock conditional +// cond.Lock(); // lock conditional + cond.Signal(); // signal changed flag to waiting "stop" method +// cond.Unlock(); // unlock conditional } diff --git a/externals/grill/flext/tutorial/thread2/thread2.cw b/externals/grill/flext/tutorial/thread2/thread2.cw index af968e69..524ad776 100755 Binary files a/externals/grill/flext/tutorial/thread2/thread2.cw and b/externals/grill/flext/tutorial/thread2/thread2.cw differ -- cgit v1.2.1