diff --git a/qse/include/qse/Types.hpp b/qse/include/qse/Types.hpp index ab5aaf17..1ccb7bb6 100644 --- a/qse/include/qse/Types.hpp +++ b/qse/include/qse/Types.hpp @@ -35,6 +35,7 @@ #include #if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) // C++11 or later + #define QSE_CPP_CPP11 1 #define QSE_CPP_NOEXCEPT noexcept(true) #define QSE_CPP_EXPLICIT explicit @@ -54,6 +55,7 @@ #elif (__cplusplus >= 199711L) // C++98 + #undef QSE_CPP_CPP11 #define QSE_CPP_NOEXCEPT throw() #define QSE_CPP_EXPLICIT diff --git a/qse/include/qse/si/Thread.hpp b/qse/include/qse/si/Thread.hpp index 1b93f617..afe515ea 100644 --- a/qse/include/qse/si/Thread.hpp +++ b/qse/include/qse/si/Thread.hpp @@ -69,29 +69,21 @@ public: virtual int stop () QSE_CPP_NOEXCEPT; - virtual int main () { return 0; } + virtual int main () { return 0; } // to be overridden by a child class. // return the context pointer value - const void* getContext () const { return this->__exctx; } - void* getContext () { return this->__exctx; } + const void* getContext () const QSE_CPP_NOEXCEPT { return this->__exctx; } + void* getContext () QSE_CPP_NOEXCEPT { return this->__exctx; } // change the context pointer value - void setContext (void* ctx) { this->__exctx = ctx; } + void setContext (void* ctx) QSE_CPP_NOEXCEPT { this->__exctx = ctx; } int join () QSE_CPP_NOEXCEPT { return qse_thr_join(this); } int detach () QSE_CPP_NOEXCEPT { return qse_thr_detach(this); } -/* - void sleep (qse_time_t msecs) - { - qse_sleep (msecs); - } -*/ int kill (int sig) QSE_CPP_NOEXCEPT { return qse_thr_kill(this, sig); } - int blockSignal (int sig) QSE_CPP_NOEXCEPT { return qse_thr_blocksig(this, sig); } int unblockSignal (int sig) QSE_CPP_NOEXCEPT { return qse_thr_unblocksig(this, sig); } - int blockAllSignals () QSE_CPP_NOEXCEPT { return qse_thr_blockallsigs (this); } int unblockAllSignals () QSE_CPP_NOEXCEPT { return qse_thr_unblockallsigs (this); } @@ -117,10 +109,10 @@ template class ThreadF: public Thread { public: - ThreadF () {} - ThreadF (const F& f): __lfunc(f) {} + ThreadF () QSE_CPP_NOEXCEPT {} + ThreadF (const F& f) QSE_CPP_NOEXCEPT: __lfunc(f) {} #if defined(QSE_CPP_ENABLE_CPP11_MOVE) - ThreadF (F&& f): __lfunc(QSE_CPP_RVREF(f)) {} + ThreadF (F&& f) QSE_CPP_NOEXCEPT: __lfunc(QSE_CPP_RVREF(f)) {} #endif static int call_func (qse_thr_t* thr, void* ctx) @@ -138,7 +130,8 @@ protected: F __lfunc; }; -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) + #if 0 // i don't want to use std::function. @@ -161,11 +154,72 @@ public: protected: std::function __lfunc; }; + +#else + +template +class ThreadL; + +template +class ThreadL: public Thread +{ +public: + ThreadL () QSE_CPP_NOEXCEPT: __lfunc(nullptr) {} + ~ThreadL () QSE_CPP_NOEXCEPT + { + if (this->__lfunc) delete this->__lfunc; + } + + static int call_func (qse_thr_t* thr, void* ctx) + { + ThreadL* t = (ThreadL*)ctx; + return t->__lfunc->invoke(t); + } + + template + int start (T&& f, int flags) QSE_CPP_NOEXCEPT + //int start (T f, int flags) QSE_CPP_NOEXCEPT + { + if (this->__state == QSE_THR_RUNNING) return -1; + if (this->__lfunc) delete this->__lfunc; + try + { + // TODO: are there any ways to achieve this without memory allocation? + this->__lfunc = new TCallable (QSE_CPP_RVREF(f)); + } + catch (...) + { + this->__lfunc = nullptr; + return -1; + } + return qse_thr_start (this, (qse_thr_rtn_t)ThreadL::call_func, this, flags); + } + +protected: + class Callable + { + public: + virtual ~Callable () QSE_CPP_NOEXCEPT {}; + virtual RT invoke (ARGS... args) = 0; + }; + + template + class TCallable: public Callable + { + public: + TCallable (const T& t) QSE_CPP_NOEXCEPT: t(t) { } + virtual ~TCallable () QSE_CPP_NOEXCEPT {} + RT invoke (ARGS... args) { return this->t(args ...); } + + private: + T t; + }; + + Callable* __lfunc; +}; #endif - - -#endif +#endif // QSE_CPP_CPP11 QSE_END_NAMESPACE(QSE) diff --git a/qse/samples/si/thr02.cpp b/qse/samples/si/thr02.cpp index 371b8315..8970dd39 100644 --- a/qse/samples/si/thr02.cpp +++ b/qse/samples/si/thr02.cpp @@ -80,9 +80,10 @@ static int func_ptr (QSE::Thread* thr) static int test1 (void) { int localstopreq = 0; + g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0); -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) auto lambda = [](QSE::Thread* thr)->int { int i = 0; @@ -128,7 +129,7 @@ static int test1 (void) QSE::ThreadR thr2; thr2.setStackSize (64000); thr2.setContext (&localstopreq); -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) // the lambda expression with no capture can be passed as a function pointer // as long as the signature matches QSE::Thread::ThreadRoutine. if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1) @@ -140,7 +141,7 @@ static int test1 (void) return -1; } -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) QSE::ThreadF thr3 (lambda); thr3.setStackSize (64000); thr3.setContext (&localstopreq); @@ -158,15 +159,38 @@ static int test1 (void) qse_printf (QSE_T("cannot start thread4\n")); return -1; } + + QSE::ThreadL thr5; + thr5.setStackSize (64000); + if (thr5.start( + ([&localstopreq, &thr5](QSE::Thread* thr) { + int i = 0; + + while (!localstopreq) + { + qse_mtx_lock (g_prmtx, QSE_NULL); + qse_printf (QSE_T("tl %p -> %d\n"), thr, i); + qse_mtx_unlock (g_prmtx); + i++; + sleep (1); + } + + return i; + }), + QSE::Thread::SIGNALS_BLOCKED) <= -1) + { + qse_printf (QSE_T("cannot start thread5\n")); + return -1; + } #endif // turn a functor to a thread - QSE::ThreadF thr5; - thr5.setStackSize (64000); - thr5.setContext (&localstopreq); - if (thr5.start(QSE::Thread::SIGNALS_BLOCKED) <= -1) + QSE::ThreadF thr6; + thr6.setStackSize (64000); + thr6.setContext (&localstopreq); + if (thr6.start(QSE::Thread::SIGNALS_BLOCKED) <= -1) { - qse_printf (QSE_T("cannot start thread4\n")); + qse_printf (QSE_T("cannot start thread6\n")); return -1; } @@ -174,11 +198,12 @@ static int test1 (void) { if (thr1.getState() == QSE::Thread::TERMINATED && thr2.getState() == QSE::Thread::TERMINATED && -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) thr3.getState() == QSE::Thread::TERMINATED && thr4.getState() == QSE::Thread::TERMINATED && + thr5.getState() == QSE::Thread::TERMINATED && #endif - thr5.getState() == QSE::Thread::TERMINATED) break; + thr6.getState() == QSE::Thread::TERMINATED) break; sleep (1); } @@ -190,19 +215,21 @@ static int test1 (void) thr1.join (); thr2.join (); -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) thr3.join (); thr4.join (); -#endif thr5.join (); +#endif + thr6.join (); qse_printf (QSE_T("thread1 ended with retcode %d\n"), thr1.getReturnCode()); qse_printf (QSE_T("thread2 ended with retcode %d\n"), thr2.getReturnCode()); -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later +#if defined(QSE_CPP_CPP11) qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.getReturnCode()); qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.getReturnCode()); -#endif qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode()); +#endif + qse_printf (QSE_T("thread6 ended with retcode %d\n"), thr6.getReturnCode()); qse_mtx_close (g_prmtx); return 0;