added support for starting functors/lambdas to Poco::Thread class
This commit is contained in:
Родитель
28982f9fcc
Коммит
7043a3d4ff
|
@ -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 <class Functor>
|
||||
void startFunc(Functor fn)
|
||||
/// Starts the thread with the given functor object or lambda.
|
||||
{
|
||||
startImpl(new FunctorRunnable<Functor>(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 Functor>
|
||||
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&);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Poco/Event.h"
|
||||
#include "Poco/RefCountedObject.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <pthread.h>
|
||||
// must be limits.h (not <climits>) for PTHREAD_STACK_MIN on Solaris
|
||||
#include <limits.h>
|
||||
|
@ -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<Runnable> 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<CallbackData> pCallbackTarget;
|
||||
SharedPtr<Runnable> pRunnableTarget;
|
||||
pthread_t thread;
|
||||
int prio;
|
||||
int osPrio;
|
||||
|
|
|
@ -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<Runnable> 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<Runnable> _pRunnableTarget;
|
||||
HANDLE _thread;
|
||||
DWORD _threadId;
|
||||
int _prio;
|
||||
int _stackSize;
|
||||
|
||||
static CurrentThreadHolder _currentThreadHolder;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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<Runnable> 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;
|
||||
|
|
|
@ -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<Runnable> 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<ThreadImpl*>(pThread));
|
||||
#if defined(POCO_WIN32_DEBUGGER_THREAD_NAMES)
|
||||
setThreadName(-1, reinterpret_cast<Thread*>(pThread)->getName().c_str());
|
||||
#endif
|
||||
try
|
||||
{
|
||||
ThreadImpl* pTI = reinterpret_cast<ThreadImpl*>(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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
void testTrySleep();
|
||||
void testThreadTarget();
|
||||
void testThreadFunction();
|
||||
void testThreadFunctor();
|
||||
void testThreadStackSize();
|
||||
void testSleep();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче