added QSE::ThreadL
This commit is contained in:
parent
8e78356337
commit
2a1cda7981
@ -35,6 +35,7 @@
|
|||||||
#include <qse/macros.h>
|
#include <qse/macros.h>
|
||||||
|
|
||||||
#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) // C++11 or later
|
#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_NOEXCEPT noexcept(true)
|
||||||
#define QSE_CPP_EXPLICIT explicit
|
#define QSE_CPP_EXPLICIT explicit
|
||||||
@ -54,6 +55,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#elif (__cplusplus >= 199711L) // C++98
|
#elif (__cplusplus >= 199711L) // C++98
|
||||||
|
#undef QSE_CPP_CPP11
|
||||||
|
|
||||||
#define QSE_CPP_NOEXCEPT throw()
|
#define QSE_CPP_NOEXCEPT throw()
|
||||||
#define QSE_CPP_EXPLICIT
|
#define QSE_CPP_EXPLICIT
|
||||||
|
@ -69,29 +69,21 @@ public:
|
|||||||
|
|
||||||
virtual int stop () QSE_CPP_NOEXCEPT;
|
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
|
// return the context pointer value
|
||||||
const void* getContext () const { return this->__exctx; }
|
const void* getContext () const QSE_CPP_NOEXCEPT { return this->__exctx; }
|
||||||
void* getContext () { return this->__exctx; }
|
void* getContext () QSE_CPP_NOEXCEPT { return this->__exctx; }
|
||||||
|
|
||||||
// change the context pointer value
|
// 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 join () QSE_CPP_NOEXCEPT { return qse_thr_join(this); }
|
||||||
int detach () QSE_CPP_NOEXCEPT { return qse_thr_detach(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 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 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 unblockSignal (int sig) QSE_CPP_NOEXCEPT { return qse_thr_unblocksig(this, sig); }
|
||||||
|
|
||||||
int blockAllSignals () QSE_CPP_NOEXCEPT { return qse_thr_blockallsigs (this); }
|
int blockAllSignals () QSE_CPP_NOEXCEPT { return qse_thr_blockallsigs (this); }
|
||||||
int unblockAllSignals () QSE_CPP_NOEXCEPT { return qse_thr_unblockallsigs (this); }
|
int unblockAllSignals () QSE_CPP_NOEXCEPT { return qse_thr_unblockallsigs (this); }
|
||||||
|
|
||||||
@ -117,10 +109,10 @@ template <typename F>
|
|||||||
class ThreadF: public Thread
|
class ThreadF: public Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ThreadF () {}
|
ThreadF () QSE_CPP_NOEXCEPT {}
|
||||||
ThreadF (const F& f): __lfunc(f) {}
|
ThreadF (const F& f) QSE_CPP_NOEXCEPT: __lfunc(f) {}
|
||||||
#if defined(QSE_CPP_ENABLE_CPP11_MOVE)
|
#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
|
#endif
|
||||||
|
|
||||||
static int call_func (qse_thr_t* thr, void* ctx)
|
static int call_func (qse_thr_t* thr, void* ctx)
|
||||||
@ -138,7 +130,8 @@ protected:
|
|||||||
F __lfunc;
|
F __lfunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later
|
#if defined(QSE_CPP_CPP11)
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// i don't want to use std::function.
|
// i don't want to use std::function.
|
||||||
@ -161,11 +154,72 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
std::function<int(ThreadF*)> __lfunc;
|
std::function<int(ThreadF*)> __lfunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ThreadL;
|
||||||
|
|
||||||
|
template <typename RT, typename... ARGS>
|
||||||
|
class ThreadL<RT(ARGS...)>: 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 <typename T>
|
||||||
|
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<T> (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 <typename T>
|
||||||
|
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
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
QSE_END_NAMESPACE(QSE)
|
QSE_END_NAMESPACE(QSE)
|
||||||
|
@ -80,9 +80,10 @@ static int func_ptr (QSE::Thread* thr)
|
|||||||
static int test1 (void)
|
static int test1 (void)
|
||||||
{
|
{
|
||||||
int localstopreq = 0;
|
int localstopreq = 0;
|
||||||
|
|
||||||
g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 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
|
auto lambda = [](QSE::Thread* thr)->int
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -128,7 +129,7 @@ static int test1 (void)
|
|||||||
QSE::ThreadR thr2;
|
QSE::ThreadR thr2;
|
||||||
thr2.setStackSize (64000);
|
thr2.setStackSize (64000);
|
||||||
thr2.setContext (&localstopreq);
|
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
|
// the lambda expression with no capture can be passed as a function pointer
|
||||||
// as long as the signature matches QSE::Thread::ThreadRoutine.
|
// as long as the signature matches QSE::Thread::ThreadRoutine.
|
||||||
if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1)
|
if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1)
|
||||||
@ -140,7 +141,7 @@ static int test1 (void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later
|
#if defined(QSE_CPP_CPP11)
|
||||||
QSE::ThreadF<decltype(lambda)> thr3 (lambda);
|
QSE::ThreadF<decltype(lambda)> thr3 (lambda);
|
||||||
thr3.setStackSize (64000);
|
thr3.setStackSize (64000);
|
||||||
thr3.setContext (&localstopreq);
|
thr3.setContext (&localstopreq);
|
||||||
@ -158,15 +159,38 @@ static int test1 (void)
|
|||||||
qse_printf (QSE_T("cannot start thread4\n"));
|
qse_printf (QSE_T("cannot start thread4\n"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSE::ThreadL<int(QSE::Thread*)> 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
|
#endif
|
||||||
|
|
||||||
// turn a functor to a thread
|
// turn a functor to a thread
|
||||||
QSE::ThreadF<Functor> thr5;
|
QSE::ThreadF<Functor> thr6;
|
||||||
thr5.setStackSize (64000);
|
thr6.setStackSize (64000);
|
||||||
thr5.setContext (&localstopreq);
|
thr6.setContext (&localstopreq);
|
||||||
if (thr5.start(QSE::Thread::SIGNALS_BLOCKED) <= -1)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,11 +198,12 @@ static int test1 (void)
|
|||||||
{
|
{
|
||||||
if (thr1.getState() == QSE::Thread::TERMINATED &&
|
if (thr1.getState() == QSE::Thread::TERMINATED &&
|
||||||
thr2.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 &&
|
thr3.getState() == QSE::Thread::TERMINATED &&
|
||||||
thr4.getState() == QSE::Thread::TERMINATED &&
|
thr4.getState() == QSE::Thread::TERMINATED &&
|
||||||
|
thr5.getState() == QSE::Thread::TERMINATED &&
|
||||||
#endif
|
#endif
|
||||||
thr5.getState() == QSE::Thread::TERMINATED) break;
|
thr6.getState() == QSE::Thread::TERMINATED) break;
|
||||||
sleep (1);
|
sleep (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,19 +215,21 @@ static int test1 (void)
|
|||||||
|
|
||||||
thr1.join ();
|
thr1.join ();
|
||||||
thr2.join ();
|
thr2.join ();
|
||||||
#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) //C++11 or later
|
#if defined(QSE_CPP_CPP11)
|
||||||
thr3.join ();
|
thr3.join ();
|
||||||
thr4.join ();
|
thr4.join ();
|
||||||
#endif
|
|
||||||
thr5.join ();
|
thr5.join ();
|
||||||
|
#endif
|
||||||
|
thr6.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());
|
||||||
#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("thread3 ended with retcode %d\n"), thr3.getReturnCode());
|
||||||
qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.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());
|
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);
|
qse_mtx_close (g_prmtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user