MXS-1489 Create mechanism for running concurrent tasks

This commit introduces maxscale::future, maxscale::packaged_task
and maxscale::thread that are modeled after C++11 std::future,
std::packaged_task and std::thread as described here:
http://en.cppreference.com/w/cpp/thread

The standard classes rely upon rvalue references (and move
constructors) introduced by C++11. As the C++ compilers we must use
are pre-C++11 that feature is obviously not present. The absence of
rvalue references is circumvented by implementing regular copy
constructors and assignment operators as if the arguments were rvalue
references.

In practice the above means that when one of these objects are copied,
the state is _moved_ rendering the copied object in default initialized
state. Some care is needed to ensure that unintended copying does not
occur.
This commit is contained in:
Johan Wikman
2017-11-07 10:03:23 +02:00
parent a96c8e1326
commit d7b8e95234
5 changed files with 740 additions and 0 deletions

View File

@ -12,6 +12,7 @@
*/
#include <maxscale/thread.h>
#include <maxscale/thread.hh>
#include <maxscale/log_manager.h>
THREAD *thread_start(THREAD *thd, void (*entry)(void *), void *arg, size_t stack_size)
@ -68,3 +69,116 @@ void thread_millisleep(int ms)
req.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&req, NULL);
}
//
// maxscale::thread
//
namespace maxscale
{
thread::thread()
: m_pInternal(NULL)
{
}
thread::thread(const thread& other)
: m_pInternal(other.m_pInternal)
{
other.m_pInternal = NULL;
}
thread& thread::operator = (const thread& rhs)
{
thread copy(rhs);
copy.swap(*this);
return *this;
}
thread::~thread()
{
ss_dassert(!joinable());
if (joinable())
{
MXS_ERROR("A thread that has not been joined is destructed.");
}
else
{
delete m_pInternal;
}
}
bool thread::joinable() const
{
return m_pInternal ? m_pInternal->joinable() : false;
}
void thread::join()
{
ss_dassert(m_pInternal);
if (!m_pInternal)
{
MXS_ERROR("Attempt to join a non-joinable thread.");
}
else
{
m_pInternal->join();
}
}
void thread::swap(thread& rhs)
{
std::swap(m_pInternal, rhs.m_pInternal);
}
void thread::run()
{
ss_dassert(m_pInternal);
m_pInternal->run();
}
thread::internal::internal(thread::task* pTask)
: m_pTask(pTask)
, m_thread(0)
{
}
thread::internal::~internal()
{
ss_info_dassert(!m_pTask, "Thread not joined before destructed.");
ss_dassert(m_thread == 0);
}
bool thread::internal::joinable() const
{
return m_thread != 0;
}
void thread::internal::join()
{
ss_dassert(joinable());
thread_wait(m_thread);
delete m_pTask;
m_pTask = NULL;
m_thread = 0;
}
void thread::internal::run()
{
if (!thread_start(&m_thread, &thread::internal::main, this, 0))
{
MXS_ALERT("Could not start thread, MaxScale is likely to malfunction.");
}
}
void thread::internal::main()
{
m_pTask->run();
}
void thread::internal::main(void* pArg)
{
static_cast<internal*>(pArg)->main();
}
}