Clean up the threading code: remove the private classes.

This commit is contained in:
Erik Hofman
2020-01-29 11:33:54 +01:00
parent 9f862dcc0e
commit 11e243a216
2 changed files with 103 additions and 166 deletions
+91 -159
View File
@@ -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();
}
} }
+12 -7
View File
@@ -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;
}; };
/// ///