added QSE::ThreadR and QSE::ThreadC
This commit is contained in:
parent
8256cee77f
commit
36d4883f6d
@ -29,9 +29,6 @@
|
|||||||
|
|
||||||
#include <qse/si/thr.h>
|
#include <qse/si/thr.h>
|
||||||
#include <qse/Uncopyable.hpp>
|
#include <qse/Uncopyable.hpp>
|
||||||
#include <qse/cmn/Mmged.hpp>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
QSE_BEGIN_NAMESPACE(QSE)
|
QSE_BEGIN_NAMESPACE(QSE)
|
||||||
|
|
||||||
@ -41,8 +38,6 @@ public:
|
|||||||
// native thread hadnle type
|
// native thread hadnle type
|
||||||
typedef qse_thr_hnd_t Handle;
|
typedef qse_thr_hnd_t Handle;
|
||||||
|
|
||||||
typedef int (*ThreadRoutine) (Thread* thr);
|
|
||||||
|
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
INCUBATING = QSE_THR_INCUBATING,
|
INCUBATING = QSE_THR_INCUBATING,
|
||||||
@ -69,45 +64,6 @@ public:
|
|||||||
qse_size_t getStackSize () const QSE_CPP_NOEXCEPT { return this->__stacksize; }
|
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); }
|
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<int(QSE::Thread*)>;
|
|
||||||
|
|
||||||
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 <typename F>
|
|
||||||
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.
|
// execute the main method defined in this class in a thread.
|
||||||
virtual int start (int flags = 0) QSE_CPP_NOEXCEPT;
|
virtual int start (int flags = 0) QSE_CPP_NOEXCEPT;
|
||||||
|
|
||||||
@ -141,17 +97,72 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void* __exctx;
|
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;
|
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);
|
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 <typename X>
|
||||||
|
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<int(LambdaThread*)> __tmplam;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
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<F>* t = (ThreadC<F>*)ctx;
|
||||||
|
return t->__lfunc (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int start (int flags = 0) QSE_CPP_NOEXCEPT
|
||||||
|
{
|
||||||
|
return qse_thr_start (this, (qse_thr_rtn_t)ThreadC<F>::call_lambda, this, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
F __lfunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
QSE_END_NAMESPACE(QSE)
|
QSE_END_NAMESPACE(QSE)
|
||||||
|
|
||||||
|
@ -49,29 +49,6 @@ Thread::~Thread () QSE_CPP_NOEXCEPT
|
|||||||
qse_thr_fini (this);
|
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)
|
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);
|
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)
|
QSE_END_NAMESPACE(QSE)
|
||||||
|
@ -39,20 +39,41 @@ public:
|
|||||||
int stopreq;
|
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)
|
static int test1 (void)
|
||||||
{
|
{
|
||||||
MyThread thr1;
|
MyThread thr1;
|
||||||
QSE::Thread thr2;
|
QSE::ThreadR thr2;
|
||||||
QSE::Thread thr3;
|
|
||||||
int localstopreq = 0;
|
|
||||||
|
|
||||||
|
int localstopreq = 0;
|
||||||
g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0);
|
g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0);
|
||||||
|
|
||||||
thr1.setStackSize (64000);
|
thr1.setStackSize (64000);
|
||||||
thr2.setStackSize (64000);
|
thr2.setStackSize (64000);
|
||||||
thr3.setStackSize (64000);
|
|
||||||
|
|
||||||
auto lambda = [](QSE::Thread* thr) {
|
|
||||||
|
auto lambda = [](QSE::Thread* thr)->int
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int* stopreqptr = (int*)thr->getContext();
|
int* stopreqptr = (int*)thr->getContext();
|
||||||
|
|
||||||
@ -68,7 +89,8 @@ static int test1 (void)
|
|||||||
return i;
|
return i;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto lambda_with_capture = [&localstopreq](QSE::Thread* thr) {
|
auto lambda_with_capture = [&localstopreq](QSE::Thread* thr)->int
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (!localstopreq)
|
while (!localstopreq)
|
||||||
@ -98,34 +120,62 @@ static int test1 (void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//QSE::LambdaThread thr3;
|
||||||
if (thr3.startl(lambda_with_capture, QSE::Thread::SIGNALS_BLOCKED) <= -1)
|
QSE::ThreadC<decltype(lambda)> thr3 (lambda);
|
||||||
|
thr3.setStackSize (64000);
|
||||||
|
thr3.setContext (&localstopreq);
|
||||||
|
if (thr3.start(QSE::Thread::SIGNALS_BLOCKED) <= -1)
|
||||||
{
|
{
|
||||||
qse_printf (QSE_T("cannot start thread3\n"));
|
qse_printf (QSE_T("cannot start thread3\n"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// turn a lambda with capture to a thread
|
||||||
|
QSE::ThreadC<decltype(lambda_with_capture)> 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<Functor> 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)
|
while (!g_stopreq)
|
||||||
{
|
{
|
||||||
if (thr1.getState() == QSE::Thread::TERMINATED &&
|
if (thr1.getState() == QSE::Thread::TERMINATED &&
|
||||||
thr2.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);
|
sleep (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_stopreq)
|
if (g_stopreq)
|
||||||
{
|
{
|
||||||
thr1.stopreq = 1;
|
|
||||||
localstopreq = 1;
|
localstopreq = 1;
|
||||||
|
thr1.stopreq = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
thr1.join ();
|
thr1.join ();
|
||||||
thr2.join ();
|
thr2.join ();
|
||||||
thr3.join ();
|
thr3.join ();
|
||||||
|
thr4.join ();
|
||||||
|
thr5.join ();
|
||||||
|
|
||||||
qse_printf (QSE_T("thread1 ended with retcode %d\n"), thr1.getReturnCode());
|
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("thread2 ended with retcode %d\n"), thr2.getReturnCode());
|
||||||
qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.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);
|
qse_mtx_close (g_prmtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user