Clean up the threading code: remove the private classes.
This commit is contained in:
+91
-159
@@ -4,6 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
|
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
|
||||||
// Copyright (C) 2011 Mathias Froehlich
|
// Copyright (C) 2011 Mathias Froehlich
|
||||||
|
// Copyright (C) 2020 Erik Hofman
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU General Public License as
|
||||||
@@ -36,178 +37,49 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
# include <list>
|
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#else
|
#else
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
# include <cassert>
|
|
||||||
# include <cerrno>
|
|
||||||
# include <sys/time.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct SGWaitCondition::PrivateData {
|
|
||||||
PrivateData(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~PrivateData(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void signal(void)
|
SGThread::SGThread()
|
||||||
{
|
|
||||||
bool waiting;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mtx);
|
|
||||||
waiting = !ready;
|
|
||||||
ready = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waiting) {
|
|
||||||
_condition.notify_one();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void broadcast(void)
|
|
||||||
{
|
|
||||||
bool waiting;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_mtx);
|
|
||||||
waiting = !ready;
|
|
||||||
ready = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waiting) {
|
|
||||||
_condition.notify_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait(std::mutex& mutex) noexcept
|
|
||||||
{
|
|
||||||
mutex.unlock();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(_mtx);
|
|
||||||
_condition.wait(lock, [this]{ return ready; } );
|
|
||||||
ready = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
# if _WIN32
|
|
||||||
// native_handle_type *m = mutex.native_handle();
|
|
||||||
// assert(m->LockCount == 0);
|
|
||||||
# else
|
|
||||||
pthread_mutex_t *m = mutex.native_handle();
|
|
||||||
assert(m->__data.__count == 0);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
mutex.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wait(std::mutex& mutex, unsigned msec) noexcept
|
|
||||||
{
|
|
||||||
auto timeout = std::chrono::milliseconds(msec);
|
|
||||||
|
|
||||||
mutex.unlock();
|
|
||||||
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(_mtx);
|
|
||||||
_condition.wait_for(lock, timeout, [this]{ return ready; } );
|
|
||||||
ready = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
# if _WIN32
|
|
||||||
// native_handle_type *m = mutex.native_handle();
|
|
||||||
// assert(m->LockCount == 0);
|
|
||||||
# else
|
|
||||||
pthread_mutex_t *m = mutex.native_handle();
|
|
||||||
assert(m->__data.__count == 0);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
mutex.lock();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::mutex _mtx;
|
|
||||||
std::condition_variable _condition;
|
|
||||||
std::atomic<std::thread::id> m_holder;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool ready = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SGThread::PrivateData {
|
|
||||||
PrivateData()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~PrivateData()
|
|
||||||
{
|
|
||||||
// If we are still having a started thread and nobody waited,
|
|
||||||
// now detach ...
|
|
||||||
if (!_started)
|
|
||||||
return;
|
|
||||||
_thread.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *start_routine(void* data)
|
|
||||||
{
|
|
||||||
SGThread* thread = reinterpret_cast<SGThread*>(data);
|
|
||||||
thread->run();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool start(SGThread& thread)
|
|
||||||
{
|
|
||||||
if (_started)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
_thread = std::thread(start_routine, &thread);
|
|
||||||
} catch (std::runtime_error &ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_started = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void join()
|
|
||||||
{
|
|
||||||
if (!_started)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_thread.join();
|
|
||||||
_started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread _thread;
|
|
||||||
bool _started = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
SGThread::SGThread() :
|
|
||||||
_privateData(new PrivateData)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SGThread::~SGThread()
|
SGThread::~SGThread()
|
||||||
{
|
{
|
||||||
delete _privateData;
|
// If we are still having a started thread and nobody waited,
|
||||||
_privateData = 0;
|
// now detach ...
|
||||||
|
if (!_started)
|
||||||
|
return;
|
||||||
|
_thread.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SGThread::start()
|
SGThread::start()
|
||||||
{
|
{
|
||||||
return _privateData->start(*this);
|
if (_started)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
_thread = std::thread(start_routine, this);
|
||||||
|
} catch (std::runtime_error &ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_started = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SGThread::join()
|
SGThread::join()
|
||||||
{
|
{
|
||||||
_privateData->join();
|
if (!_started)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_thread.join();
|
||||||
|
_started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
long SGThread::current( void )
|
long SGThread::current( void )
|
||||||
@@ -219,40 +91,100 @@ long SGThread::current( void )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *SGThread::start_routine(void* data)
|
||||||
|
{
|
||||||
|
SGThread* thread = reinterpret_cast<SGThread*>(data);
|
||||||
|
thread->run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
SGWaitCondition::SGWaitCondition() :
|
|
||||||
_privateData(new PrivateData)
|
SGWaitCondition::SGWaitCondition()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SGWaitCondition::~SGWaitCondition()
|
SGWaitCondition::~SGWaitCondition()
|
||||||
{
|
{
|
||||||
delete _privateData;
|
|
||||||
_privateData = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SGWaitCondition::wait(std::mutex& mutex)
|
SGWaitCondition::wait(std::mutex& mutex)
|
||||||
{
|
{
|
||||||
_privateData->wait(mutex);
|
#ifndef NDEBUG
|
||||||
|
try {
|
||||||
|
mutex.unlock();
|
||||||
|
} catch(const std::system_error& e) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unlocking error " << e.what() );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
mutex.unlock();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mtx);
|
||||||
|
_condition.wait(lock, [this]{ return ready; } );
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
try {
|
||||||
|
mutex.lock();
|
||||||
|
} catch(const std::system_error& e) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Locking error " << e.what() );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
mutex.lock();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SGWaitCondition::wait(std::mutex& mutex, unsigned msec)
|
SGWaitCondition::wait(std::mutex& mutex, unsigned msec)
|
||||||
{
|
{
|
||||||
return _privateData->wait(mutex, msec);
|
auto timeout = std::chrono::milliseconds(msec);
|
||||||
|
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mtx);
|
||||||
|
_condition.wait_for(lock, timeout, [this]{ return ready; } );
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SGWaitCondition::signal()
|
SGWaitCondition::signal()
|
||||||
{
|
{
|
||||||
_privateData->signal();
|
bool waiting;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mtx);
|
||||||
|
waiting = !ready;
|
||||||
|
ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waiting) {
|
||||||
|
_condition.notify_one();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SGWaitCondition::broadcast()
|
SGWaitCondition::broadcast()
|
||||||
{
|
{
|
||||||
_privateData->broadcast();
|
bool waiting;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mtx);
|
||||||
|
waiting = !ready;
|
||||||
|
ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waiting) {
|
||||||
|
_condition.notify_all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
//
|
//
|
||||||
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
|
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
|
||||||
// Copyright (C) 2011 Mathias Froehlich
|
// Copyright (C) 2011 Mathias Froehlich
|
||||||
|
// Copyright (C) 2020 Erik Hofman
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU General Public License as
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
#ifndef SGTHREAD_HXX_INCLUDED
|
#ifndef SGTHREAD_HXX_INCLUDED
|
||||||
#define SGTHREAD_HXX_INCLUDED 1
|
#define SGTHREAD_HXX_INCLUDED 1
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -78,18 +80,20 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void run() = 0;
|
virtual void run() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General thread starter routine.
|
||||||
|
*/
|
||||||
|
static void *start_routine(void* data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Disable copying.
|
// Disable copying.
|
||||||
SGThread(const SGThread&);
|
SGThread(const SGThread&);
|
||||||
SGThread& operator=(const SGThread&);
|
SGThread& operator=(const SGThread&);
|
||||||
|
|
||||||
struct PrivateData;
|
std::thread _thread;
|
||||||
PrivateData* _privateData;
|
bool _started = false;
|
||||||
|
|
||||||
friend struct PrivateData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SGWaitCondition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A condition variable is a synchronization device that allows threads to
|
* A condition variable is a synchronization device that allows threads to
|
||||||
@@ -146,8 +150,9 @@ private:
|
|||||||
SGWaitCondition(const SGWaitCondition&);
|
SGWaitCondition(const SGWaitCondition&);
|
||||||
SGWaitCondition& operator=(const SGWaitCondition&);
|
SGWaitCondition& operator=(const SGWaitCondition&);
|
||||||
|
|
||||||
struct PrivateData;
|
bool ready = false;
|
||||||
PrivateData* _privateData;
|
std::mutex _mtx;
|
||||||
|
std::condition_variable _condition;
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user