diff --git a/Foundation/include/Poco/Thread.h b/Foundation/include/Poco/Thread.h index 541fa1bdc..d5653292c 100644 --- a/Foundation/include/Poco/Thread.h +++ b/Foundation/include/Poco/Thread.h @@ -122,7 +122,7 @@ public: /// May return 0 if the priority has not been explicitly set. static int getMinOSPriority(int policy = POLICY_DEFAULT); - /// Returns the mininum operating system-specific priority value, + /// Returns the minimum operating system-specific priority value, /// which can be passed to setOSPriority() for the given policy. static int getMaxOSPriority(int policy = POLICY_DEFAULT); @@ -149,6 +149,13 @@ public: void start(Callable target, void* pData = 0); /// Starts the thread with the given target and parameter. + template + void startFunc(Functor fn) + /// Starts the thread with the given functor object or lambda. + { + startImpl(new FunctorRunnable(fn)); + } + void join(); /// Waits until the thread completes execution. /// If multiple threads try to join the same @@ -221,7 +228,29 @@ protected: static int uniqueId(); /// Creates and returns a unique id for a thread. - + + template + class FunctorRunnable: public Runnable + { + public: + FunctorRunnable(const Functor& functor): + _functor(functor) + { + } + + ~FunctorRunnable() + { + } + + void run() + { + _functor(); + } + + private: + Functor _functor; + }; + private: Thread(const Thread&); Thread& operator = (const Thread&); diff --git a/Foundation/include/Poco/Thread_POSIX.h b/Foundation/include/Poco/Thread_POSIX.h index 120f7a86e..5c6e945de 100644 --- a/Foundation/include/Poco/Thread_POSIX.h +++ b/Foundation/include/Poco/Thread_POSIX.h @@ -26,6 +26,7 @@ #include "Poco/Event.h" #include "Poco/RefCountedObject.h" #include "Poco/AutoPtr.h" +#include "Poco/SharedPtr.h" #include // must be limits.h (not ) for PTHREAD_STACK_MIN on Solaris #include @@ -61,16 +62,6 @@ public: POLICY_DEFAULT_IMPL = SCHED_OTHER }; - struct CallbackData: public RefCountedObject - { - CallbackData(): callback(0), pData(0) - { - } - - Callable callback; - void* pData; - }; - ThreadImpl(); ~ThreadImpl(); @@ -83,9 +74,7 @@ public: static int getMaxOSPriorityImpl(int policy); void setStackSizeImpl(int size); int getStackSizeImpl() const; - void startImpl(Runnable& target); - void startImpl(Callable target, void* pData = 0); - + void startImpl(SharedPtr pTarget); void joinImpl(); bool joinImpl(long milliseconds); bool isRunningImpl() const; @@ -129,8 +118,6 @@ private: struct ThreadData: public RefCountedObject { ThreadData(): - pRunnableTarget(0), - pCallbackTarget(0), thread(0), prio(PRIO_NORMAL_IMPL), policy(SCHED_OTHER), @@ -146,8 +133,7 @@ private: #endif } - Runnable* pRunnableTarget; - AutoPtr pCallbackTarget; + SharedPtr pRunnableTarget; pthread_t thread; int prio; int osPrio; diff --git a/Foundation/include/Poco/Thread_WIN32.h b/Foundation/include/Poco/Thread_WIN32.h index a954c2a4a..598db8e7a 100644 --- a/Foundation/include/Poco/Thread_WIN32.h +++ b/Foundation/include/Poco/Thread_WIN32.h @@ -22,6 +22,7 @@ #include "Poco/Foundation.h" #include "Poco/Runnable.h" +#include "Poco/SharedPtr.h" #include "Poco/UnWindows.h" @@ -40,16 +41,6 @@ public: typedef unsigned (__stdcall *Entry)(void*); #endif - struct CallbackData - { - CallbackData(): callback(0), pData(0) - { - } - - Callable callback; - void* pData; - }; - enum Priority { PRIO_LOWEST_IMPL = THREAD_PRIORITY_LOWEST, @@ -76,9 +67,7 @@ public: static int getMaxOSPriorityImpl(int policy); void setStackSizeImpl(int size); int getStackSizeImpl() const; - void startImpl(Runnable& target); - void startImpl(Callable target, void* pData = 0); - + void startImpl(SharedPtr pTarget); void joinImpl(); bool joinImpl(long milliseconds); bool isRunningImpl() const; @@ -94,12 +83,6 @@ protected: static unsigned __stdcall runnableEntry(void* pThread); #endif -#if defined(_DLL) - static DWORD WINAPI callableEntry(LPVOID pThread); -#else - static unsigned __stdcall callableEntry(void* pThread); -#endif - void createImpl(Entry ent, void* pData); void threadCleanup(); @@ -129,12 +112,11 @@ private: DWORD _slot; }; - Runnable* _pRunnableTarget; - CallbackData _callbackTarget; - HANDLE _thread; - DWORD _threadId; - int _prio; - int _stackSize; + SharedPtr _pRunnableTarget; + HANDLE _thread; + DWORD _threadId; + int _prio; + int _stackSize; static CurrentThreadHolder _currentThreadHolder; }; diff --git a/Foundation/src/Thread.cpp b/Foundation/src/Thread.cpp index 2b55fed79..e4a87dad0 100644 --- a/Foundation/src/Thread.cpp +++ b/Foundation/src/Thread.cpp @@ -38,6 +38,57 @@ namespace Poco { +namespace { + +class RunnableHolder: public Runnable +{ +public: + RunnableHolder(Runnable& target): + _target(target) + { + } + + ~RunnableHolder() + { + } + + void run() + { + _target.run(); + } + +private: + Runnable& _target; +}; + + +class CallableHolder: public Runnable +{ +public: + CallableHolder(Thread::Callable callable, void* pData): + _callable(callable), + _pData(pData) + { + } + + ~CallableHolder() + { + } + + void run() + { + _callable(_pData); + } + +private: + Thread::Callable _callable; + void* _pData; +}; + + +} // namespace + + Thread::Thread(): _id(uniqueId()), _name(makeName()), @@ -76,13 +127,13 @@ Thread::Priority Thread::getPriority() const void Thread::start(Runnable& target) { - startImpl(target); + startImpl(new RunnableHolder(target)); } void Thread::start(Callable target, void* pData) { - startImpl(target, pData); + startImpl(new CallableHolder(target, pData)); } diff --git a/Foundation/src/Thread_POSIX.cpp b/Foundation/src/Thread_POSIX.cpp index ae9707769..e64368190 100644 --- a/Foundation/src/Thread_POSIX.cpp +++ b/Foundation/src/Thread_POSIX.cpp @@ -104,7 +104,10 @@ void ThreadImpl::setPriorityImpl(int prio) _pData->policy = SCHED_OTHER; if (isRunningImpl()) { - struct sched_param par; + struct sched_param par; struct MyStruct + { + + }; par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER); if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par)) throw SystemException("cannot set thread priority"); @@ -177,7 +180,7 @@ void ThreadImpl::setStackSizeImpl(int size) } -void ThreadImpl::startImpl(Runnable& target) +void ThreadImpl::startImpl(SharedPtr pTarget) { if (_pData->pRunnableTarget) throw SystemException("thread already running"); @@ -194,7 +197,7 @@ void ThreadImpl::startImpl(Runnable& target) } } - _pData->pRunnableTarget = ⌖ + _pData->pRunnableTarget = pTarget; if (pthread_create(&_pData->thread, &attributes, runnableEntry, this)) { _pData->pRunnableTarget = 0; @@ -224,56 +227,6 @@ void ThreadImpl::startImpl(Runnable& target) } -void ThreadImpl::startImpl(Callable target, void* pData) -{ - if (_pData->pCallbackTarget && _pData->pCallbackTarget->callback) - throw SystemException("thread already running"); - - pthread_attr_t attributes; - pthread_attr_init(&attributes); - - if (_pData->stackSize != 0) - { - if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize)) - throw SystemException("can not set thread stack size"); - } - - if (0 == _pData->pCallbackTarget.get()) - _pData->pCallbackTarget = new CallbackData; - - _pData->pCallbackTarget->callback = target; - _pData->pCallbackTarget->pData = pData; - - if (pthread_create(&_pData->thread, &attributes, callableEntry, this)) - { - _pData->pCallbackTarget->callback = 0; - _pData->pCallbackTarget->pData = 0; - pthread_attr_destroy(&attributes); - throw SystemException("cannot start thread"); - } - _pData->started = true; - pthread_attr_destroy(&attributes); - - if (_pData->policy == SCHED_OTHER) - { - if (_pData->prio != PRIO_NORMAL_IMPL) - { - struct sched_param par; - par.sched_priority = mapPrio(_pData->prio, SCHED_OTHER); - if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par)) - throw SystemException("cannot set thread priority"); - } - } - else - { - struct sched_param par; - par.sched_priority = _pData->osPrio; - if (pthread_setschedparam(_pData->thread, _pData->policy, &par)) - throw SystemException("cannot set thread priority"); - } -} - - void ThreadImpl::joinImpl() { if (!_pData->started) return; diff --git a/Foundation/src/Thread_WIN32.cpp b/Foundation/src/Thread_WIN32.cpp index 8a6c34f04..0eb2c4c4f 100644 --- a/Foundation/src/Thread_WIN32.cpp +++ b/Foundation/src/Thread_WIN32.cpp @@ -70,7 +70,6 @@ ThreadImpl::CurrentThreadHolder ThreadImpl::_currentThreadHolder; ThreadImpl::ThreadImpl(): - _pRunnableTarget(0), _thread(0), _threadId(0), _prio(PRIO_NORMAL_IMPL), @@ -105,30 +104,16 @@ void ThreadImpl::setOSPriorityImpl(int prio, int /* policy */) } -void ThreadImpl::startImpl(Runnable& target) +void ThreadImpl::startImpl(SharedPtr pTarget) { if (isRunningImpl()) throw SystemException("thread already running"); - _pRunnableTarget = ⌖ - + _pRunnableTarget = pTarget; createImpl(runnableEntry, this); } -void ThreadImpl::startImpl(Callable target, void* pData) -{ - if (isRunningImpl()) - throw SystemException("thread already running"); - - threadCleanup(); - _callbackTarget.callback = target; - _callbackTarget.pData = pData; - - createImpl(callableEntry, this); -} - - void ThreadImpl::createImpl(Entry ent, void* pData) { #if defined(_DLL) @@ -237,35 +222,4 @@ unsigned __stdcall ThreadImpl::runnableEntry(void* pThread) } -#if defined(_DLL) -DWORD WINAPI ThreadImpl::callableEntry(LPVOID pThread) -#else -unsigned __stdcall ThreadImpl::callableEntry(void* pThread) -#endif -{ - _currentThreadHolder.set(reinterpret_cast(pThread)); -#if defined(POCO_WIN32_DEBUGGER_THREAD_NAMES) - setThreadName(-1, reinterpret_cast(pThread)->getName().c_str()); -#endif - try - { - ThreadImpl* pTI = reinterpret_cast(pThread); - pTI->_callbackTarget.callback(pTI->_callbackTarget.pData); - } - catch (Exception& exc) - { - ErrorHandler::handle(exc); - } - catch (std::exception& exc) - { - ErrorHandler::handle(exc); - } - catch (...) - { - ErrorHandler::handle(); - } - return 0; -} - - } // namespace Poco diff --git a/Foundation/testsuite/src/ThreadTest.cpp b/Foundation/testsuite/src/ThreadTest.cpp index 1509e6e4b..b3cb70746 100644 --- a/Foundation/testsuite/src/ThreadTest.cpp +++ b/Foundation/testsuite/src/ThreadTest.cpp @@ -363,6 +363,44 @@ void ThreadTest::testThreadFunction() } +void ThreadTest::testThreadFunctor() +{ + struct Functor + { + void operator () () + { + ++MyRunnable::_staticVar; + } + }; + + Thread thread; + + assert (!thread.isRunning()); + + MyRunnable::_staticVar = 0; + thread.startFunc(Functor()); + thread.join(); + assert (1 == MyRunnable::_staticVar); + + assert (!thread.isRunning()); + +#if __cplusplus >= 201103L + + Thread thread2; + + assert (!thread2.isRunning()); + + MyRunnable::_staticVar = 0; + thread.startFunc([] () {MyRunnable::_staticVar++;}); + thread.join(); + assert (1 == MyRunnable::_staticVar); + + assert (!thread2.isRunning()); + +#endif +} + + void ThreadTest::testThreadStackSize() { int stackSize = 50000000; @@ -436,6 +474,7 @@ CppUnit::Test* ThreadTest::suite() CppUnit_addTest(pSuite, ThreadTest, testTrySleep); CppUnit_addTest(pSuite, ThreadTest, testThreadTarget); CppUnit_addTest(pSuite, ThreadTest, testThreadFunction); + CppUnit_addTest(pSuite, ThreadTest, testThreadFunctor); CppUnit_addTest(pSuite, ThreadTest, testThreadStackSize); CppUnit_addTest(pSuite, ThreadTest, testSleep); diff --git a/Foundation/testsuite/src/ThreadTest.h b/Foundation/testsuite/src/ThreadTest.h index b984e869c..3e9f50dae 100644 --- a/Foundation/testsuite/src/ThreadTest.h +++ b/Foundation/testsuite/src/ThreadTest.h @@ -37,6 +37,7 @@ public: void testTrySleep(); void testThreadTarget(); void testThreadFunction(); + void testThreadFunctor(); void testThreadStackSize(); void testSleep();