added support for starting functors/lambdas to Poco::Thread class

This commit is contained in:
Günter Obiltschnig 2014-11-16 20:43:19 +01:00
Родитель 28982f9fcc
Коммит 7043a3d4ff
8 изменённых файлов: 142 добавлений и 147 удалений

Просмотреть файл

@ -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 = &target;
_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 = &target;
_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();