added QSE::ThreadR and QSE::ThreadC
This commit is contained in:
		| @ -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; | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user