From 36d4883f6d9059f500e5167526eddf7da75a8964 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 27 Jan 2018 16:35:02 +0000 Subject: [PATCH] added QSE::ThreadR and QSE::ThreadC --- qse/include/qse/si/Thread.hpp | 109 +++++++++++++++++++--------------- qse/lib/si/Thread.cpp | 48 ++++++++------- qse/lib/si/thr.c | 2 +- qse/samples/si/thr02.cpp | 70 ++++++++++++++++++---- 4 files changed, 146 insertions(+), 83 deletions(-) diff --git a/qse/include/qse/si/Thread.hpp b/qse/include/qse/si/Thread.hpp index 151d174b..62ee2cdc 100644 --- a/qse/include/qse/si/Thread.hpp +++ b/qse/include/qse/si/Thread.hpp @@ -29,9 +29,6 @@ #include #include -#include - -#include QSE_BEGIN_NAMESPACE(QSE) @@ -41,8 +38,6 @@ public: // native thread hadnle type typedef qse_thr_hnd_t Handle; - typedef int (*ThreadRoutine) (Thread* thr); - enum State { INCUBATING = QSE_THR_INCUBATING, @@ -69,45 +64,6 @@ public: qse_size_t getStackSize () const QSE_CPP_NOEXCEPT { return this->__stacksize; } void setStackSize (qse_size_t num) QSE_CPP_NOEXCEPT { qse_thr_setstacksize(this, num); } - -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later - using ThreadLambda = std::function; - - static int call_lambda (qse_thr_t* thr, void* ctx) - { - Thread* t = (Thread*)ctx; - return t->__tmplam (t); - } - - int startl (ThreadLambda&& f, int flags) - { - this->__tmplam = QSE_CPP_RVREF(f); - return qse_thr_start (this, (qse_thr_rtn_t)Thread::call_lambda, this, flags); - } - -#if 0 - static int call_lambda_lx (qse_thr_t* thr, void* ctx) - { - Thread* t = (Thread*)ctx; - //return ([]int(QSE::Thread*))t->__tmpvoid (t); - } - - template - int startlx (F&& f, int flags) - { - this->__tmplam = QSE_CPP_RVREF(f); - auto xx = QSE_CPP_RVREF(f); - this->__tmpvoid = (void*)&xx; - return qse_thr_start (this, (qse_thr_rtn_t)Thread::call_lambda_lx, this, flags); - } -#endif - -#endif - - - // execute the given function in a thread. - virtual int start (ThreadRoutine rtn, int flags = 0) QSE_CPP_NOEXCEPT; - // execute the main method defined in this class in a thread. virtual int start (int flags = 0) QSE_CPP_NOEXCEPT; @@ -141,17 +97,72 @@ public: protected: void* __exctx; - ThreadRoutine __tmprtn; -#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later - ThreadLambda __tmplam; -// void* __tmpvoid; -#endif static Handle INVALID_HANDLE; +}; +class ThreadR: public Thread +{ +public: + typedef int (*ThreadRoutine) (Thread* thr); + // execute the given function in a thread. + virtual int start (ThreadRoutine rtn, int flags = 0) QSE_CPP_NOEXCEPT; + +protected: + ThreadRoutine __tmprtn; static int thr_func_call_rtn (qse_thr_t* rtn, void* ctx); }; +#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later + +#if 0 +// i don't want to use std::function. +class LambdaThread: public Thread +{ +public: + static int call_lambda (qse_thr_t* thr, void* ctx) + { + LambdaThread* t = (LambdaThread*)ctx; + return t->__tmplam (t); + } + + template + int startl (X&& f, int flags) QSE_CPP_NOEXCEPT + { + this->__tmplam = QSE_CPP_RVREF(f); + return qse_thr_start (this, (qse_thr_rtn_t)LambdaThread::call_lambda, this, flags); + } + +protected: + std::function __tmplam; +}; +#endif + +template +class ThreadC: public Thread +{ +public: + ThreadC () {} + ThreadC (F& f): __lfunc(f) { } + //ThreadC (F&& f): __lfunc(QSE_CPP_RVREF(f)) { } + + static int call_lambda (qse_thr_t* thr, void* ctx) + { + ThreadC* t = (ThreadC*)ctx; + return t->__lfunc (t); + } + + int start (int flags = 0) QSE_CPP_NOEXCEPT + { + return qse_thr_start (this, (qse_thr_rtn_t)ThreadC::call_lambda, this, flags); + } + +protected: + F __lfunc; +}; + +#endif + QSE_END_NAMESPACE(QSE) diff --git a/qse/lib/si/Thread.cpp b/qse/lib/si/Thread.cpp index 39853842..681f2140 100644 --- a/qse/lib/si/Thread.cpp +++ b/qse/lib/si/Thread.cpp @@ -49,29 +49,6 @@ Thread::~Thread () QSE_CPP_NOEXCEPT qse_thr_fini (this); } -int Thread::thr_func_call_rtn (qse_thr_t* thr, void* ctx) -{ - // 'thr' may not be point to the actual Thread - // for the reason stated in Thread::start(). - // utilize the ctx pointer passed in Thread::start(). - Thread* t = (Thread*)ctx; - return t->__tmprtn(t); -} - -int Thread::start (ThreadRoutine rtn, int flags) QSE_CPP_NOEXCEPT -{ - if (this->__state == QSE_THR_RUNNING) return -1; - - // this != (qse_thr_t*)this may not be equal if this class - // has some internal added data fields. e.g. it contains - // a virtual function. direct invocation without the extra ctx pointer - // like this has some implications when attempting to convert - // qse_thr_t* to Thread*. - // qse_thr_start (this, (qse_thr_rtn_t)rtn, QSE_NULL, flags); - // so i pass a void pointer 'this' as the third argument. - this->__tmprtn = rtn; - return qse_thr_start(this, thr_func_call_rtn, this, flags); -} static int thr_func_call_main (qse_thr_t* thr, void* ctx) { @@ -93,4 +70,29 @@ int Thread::stop () QSE_CPP_NOEXCEPT return qse_thr_stop(this); } + +int ThreadR::thr_func_call_rtn (qse_thr_t* thr, void* ctx) +{ + // 'thr' may not be point to the actual Thread + // for the reason stated in Thread::start(). + // utilize the ctx pointer passed in Thread::start(). + ThreadR* t = (ThreadR*)ctx; + return t->__tmprtn(t); +} + +int ThreadR::start (ThreadRoutine rtn, int flags) QSE_CPP_NOEXCEPT +{ + if (this->__state == QSE_THR_RUNNING) return -1; + + // this != (qse_thr_t*)this may not be equal if this class + // has some internal added data fields. e.g. it contains + // a virtual function. direct invocation without the extra ctx pointer + // like this has some implications when attempting to convert + // qse_thr_t* to Thread*. + // qse_thr_start (this, (qse_thr_rtn_t)rtn, QSE_NULL, flags); + // so i pass a void pointer 'this' as the third argument. + this->__tmprtn = rtn; + return qse_thr_start(this, thr_func_call_rtn, this, flags); +} + QSE_END_NAMESPACE(QSE) diff --git a/qse/lib/si/thr.c b/qse/lib/si/thr.c index 16dc1c11..78fd1cba 100644 --- a/qse/lib/si/thr.c +++ b/qse/lib/si/thr.c @@ -113,7 +113,7 @@ static void* __thread_main (void* arg) qse_thr_blockallsigs (thr); else qse_thr_unblockallsigs (thr); - + while (thr->__state != QSE_THR_RUNNING) { #if defined(_WIN32) diff --git a/qse/samples/si/thr02.cpp b/qse/samples/si/thr02.cpp index 726cf65c..a553686d 100644 --- a/qse/samples/si/thr02.cpp +++ b/qse/samples/si/thr02.cpp @@ -39,20 +39,41 @@ public: int stopreq; }; +class Functor +{ +public: + int operator() (QSE::Thread* thr) + { + int i = 0; + int* stopreqptr = (int*)thr->getContext(); + + while (!*stopreqptr) + { + qse_mtx_lock (g_prmtx, QSE_NULL); + qse_printf (QSE_T("fc %p -> %d\n"), this, i); + qse_mtx_unlock (g_prmtx); + i++; + sleep (1); + } + + return i; + } +}; + static int test1 (void) { MyThread thr1; - QSE::Thread thr2; - QSE::Thread thr3; - int localstopreq = 0; + QSE::ThreadR thr2; + int localstopreq = 0; g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0); thr1.setStackSize (64000); thr2.setStackSize (64000); - thr3.setStackSize (64000); + - auto lambda = [](QSE::Thread* thr) { + auto lambda = [](QSE::Thread* thr)->int + { int i = 0; int* stopreqptr = (int*)thr->getContext(); @@ -68,7 +89,8 @@ static int test1 (void) return i; }; - auto lambda_with_capture = [&localstopreq](QSE::Thread* thr) { + auto lambda_with_capture = [&localstopreq](QSE::Thread* thr)->int + { int i = 0; while (!localstopreq) @@ -98,34 +120,62 @@ static int test1 (void) return -1; } - - if (thr3.startl(lambda_with_capture, QSE::Thread::SIGNALS_BLOCKED) <= -1) + //QSE::LambdaThread thr3; + QSE::ThreadC thr3 (lambda); + thr3.setStackSize (64000); + thr3.setContext (&localstopreq); + if (thr3.start(QSE::Thread::SIGNALS_BLOCKED) <= -1) { qse_printf (QSE_T("cannot start thread3\n")); return -1; } + // turn a lambda with capture to a thread + QSE::ThreadC thr4 (lambda_with_capture); + thr4.setStackSize (64000); + if (thr4.start(QSE::Thread::SIGNALS_BLOCKED) <= -1) + { + qse_printf (QSE_T("cannot start thread4\n")); + return -1; + } + + // turn a functor to a thread + QSE::ThreadC thr5; + thr5.setStackSize (64000); + thr5.setContext (&localstopreq); + if (thr5.start(QSE::Thread::SIGNALS_BLOCKED) <= -1) + { + qse_printf (QSE_T("cannot start thread4\n")); + return -1; + } while (!g_stopreq) { if (thr1.getState() == QSE::Thread::TERMINATED && thr2.getState() == QSE::Thread::TERMINATED && - thr3.getState() == QSE::Thread::TERMINATED) break; + thr3.getState() == QSE::Thread::TERMINATED && + thr4.getState() == QSE::Thread::TERMINATED && + thr5.getState() == QSE::Thread::TERMINATED) break; sleep (1); } if (g_stopreq) { - thr1.stopreq = 1; localstopreq = 1; + thr1.stopreq = 1; } thr1.join (); thr2.join (); thr3.join (); + thr4.join (); + thr5.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()); qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.getReturnCode()); + qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.getReturnCode()); + qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode()); qse_mtx_close (g_prmtx); return 0;