Skip to content

Commit

Permalink
COMMON: Use std::thread instead of Boost.Thread
Browse files Browse the repository at this point in the history
  • Loading branch information
DrMcCoy committed Mar 16, 2019
1 parent c3df597 commit 61c5034
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 34 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ else(ICONV_SECOND_ARGUMENT_IS_CONST)
add_definitions(-DICONV_CONST=)
endif(ICONV_SECOND_ARGUMENT_IS_CONST)

# pthreads, for our unit tests
# pthreads
if(NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "MinGW")
find_package(Threads)
endif()
Expand Down
85 changes: 70 additions & 15 deletions src/common/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,93 @@
* Threading helpers.
*/

#include <system_error>

#include "src/common/thread.h"
#include "src/common/util.h"

namespace Common {

Thread::Thread() : _shouldQuit(false) {
Thread::Thread() : _killThread(false), _threadRunning(false) {
}

Thread::~Thread() {
destroyThread();
}

bool Thread::createThread(const UString &name) {
if (_threadRunning.load(boost::memory_order_relaxed)) {
if (_name == name) {
warning("Thread::createThread(): Thread \"%s\" already running", _name.c_str());
return true;
}

warning("Thread::createThread(): Thread \"%s\" already running and trying to rename to \"%s\"", _name.c_str(), name.c_str());
return false;
}

_name = name;

// Try to create the thread
try {
destroyThread();
} catch (...) {
_thread = std::thread(threadHelper, static_cast<void *>(this));
} catch (const std::system_error &) {
return false;
}

return true;
}

void Thread::createThread() {
// Make sure the boost::thread is a not-a-thread (not already running)
assert(_thread.get_id() == boost::thread::id());
bool Thread::destroyThread() {
if (!_threadRunning.load(boost::memory_order_seq_cst)) {
if (_thread.joinable())
_thread.join();

_shouldQuit = false;
return true;
}

// Create the thread using the ThreadHelper and give it this instance to work on
_thread = boost::thread(ThreadHelper(), this);
}
// Signal the thread that it should die
_killThread.store(true, boost::memory_order_seq_cst);

void Thread::destroyThread() {
_shouldQuit = true;
// Wait a whole second for the thread to finish on its own
for (int i = 0; _threadRunning.load(boost::memory_order_seq_cst) && (i < 100); i++)
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(10));

_thread.join();
_killThread.store(false, boost::memory_order_seq_cst);

const bool stillRunning = _threadRunning.load(boost::memory_order_seq_cst);

/* Clean up the thread if it's not still running. If the thread is still running,
* this would block, potentially indefinitely, so we leak instead in that case.
*/
if (!stillRunning)
_thread.join();
else
_thread.detach();

/* TODO:: If we get threads that we start and stop multiple times within the runtime
* of xoreos, we might need to do something more aggressive here, like throw. */
if (stillRunning) {
warning("Thread::destroyThread(): Thread \"%s\" still running", _name.c_str());
return false;
}

return true;
}

bool Thread::shouldQuitThread() const {
return _shouldQuit;
int Thread::threadHelper(void *obj) {
Thread *thread = static_cast<Thread *>(obj);

// The thread is running.
thread->_threadRunning.store(true, boost::memory_order_relaxed);

// Run the thread
thread->threadMethod();

// Thread thread is not running.
thread->_threadRunning.store(false, boost::memory_order_relaxed);

return 0;
}

} // End of namespace Common
32 changes: 15 additions & 17 deletions src/common/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@
#ifndef COMMON_THREAD_H
#define COMMON_THREAD_H

#include "src/common/atomic.h"
#if defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS)
#include "external/mingw-std-threads/mingw.thread.h"
#else
#include <thread>
#endif

#include <boost/noncopyable.hpp>

#include <boost/thread/thread.hpp>
#include "src/common/atomic.h"
#include "src/common/ustring.h"

namespace Common {

Expand All @@ -39,28 +44,21 @@ class Thread : boost::noncopyable {
Thread();
virtual ~Thread();

protected:
/** Create and run the thread. */
void createThread();
/** Request the thread to quit and wait for it to finish. */
void destroyThread();
bool createThread(const UString &name = "");
bool destroyThread();

/** The thread method should call this periodically to query if it should quit. */
bool shouldQuitThread() const;
protected:
boost::atomic<bool> _killThread;

private:
struct ThreadHelper {
void operator()(Thread *thread) {
thread->threadMethod();
}
};
std::thread _thread;
Common::UString _name;

boost::thread _thread;
boost::atomic<bool> _shouldQuit;
boost::atomic<bool> _threadRunning;

virtual void threadMethod() = 0;

friend struct ThreadHelper;
static int threadHelper(void *obj);
};

} // End of namespace Common
Expand Down
2 changes: 1 addition & 1 deletion src/sound/sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ void SoundManager::freeChannel(size_t channel) {
}

void SoundManager::threadMethod() {
while (!shouldQuitThread()) {
while (!_killThread.load(boost::memory_order_relaxed)) {
update();
_needUpdate.wait(100);
}
Expand Down

0 comments on commit 61c5034

Please sign in to comment.