Use std::thread, std::mutex and std::condition_variable everywhere

This commit is contained in:
Benau 2020-04-11 11:01:18 +08:00
parent b6e9fcd801
commit 9157fb43f0
7 changed files with 47 additions and 124 deletions

View File

@ -29,11 +29,12 @@
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/vs.hpp" #include "utils/vs.hpp"
#include <pthread.h>
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <functional>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits> #include <limits>
@ -91,28 +92,9 @@ SFXManager::SFXManager()
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound) if (UserConfigParams::m_enable_sound)
{ {
pthread_cond_init(&m_cond_request, NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
m_thread_id.setAtomic(new pthread_t());
// The thread is created even if there atm sfx are disabled // The thread is created even if there atm sfx are disabled
// (since the user might enable it later). // (since the user might enable it later).
int error = pthread_create(m_thread_id.getData(), &attr, m_thread = std::thread(std::bind(mainLoop, this));
&SFXManager::mainLoop, this);
if (error)
{
m_thread_id.lock();
delete m_thread_id.getData();
m_thread_id.unlock();
m_thread_id.setAtomic(0);
Log::error("SFXManager", "Could not create thread, error=%d.",
errno);
}
pthread_attr_destroy(&attr);
setMasterSFXVolume( UserConfigParams::m_sfx_volume ); setMasterSFXVolume( UserConfigParams::m_sfx_volume );
m_sfx_commands.lock(); m_sfx_commands.lock();
m_sfx_commands.getData().clear(); m_sfx_commands.getData().clear();
@ -129,11 +111,7 @@ SFXManager::~SFXManager()
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound) if (UserConfigParams::m_enable_sound)
{ {
m_thread_id.lock(); m_thread.join();
pthread_join(*m_thread_id.getData(), NULL);
delete m_thread_id.getData();
m_thread_id.unlock();
pthread_cond_destroy(&m_cond_request);
} }
#endif #endif
@ -346,7 +324,7 @@ void SFXManager::stopThread()
{ {
queue(SFX_EXIT); queue(SFX_EXIT);
// Make sure the thread wakes up. // Make sure the thread wakes up.
pthread_cond_signal(&m_cond_request); m_condition_variable.notify_one();
} }
else else
#endif #endif
@ -361,16 +339,16 @@ void SFXManager::stopThread()
* in order to avoid rendering delays. * in order to avoid rendering delays.
* \param obj A pointer to the SFX singleton. * \param obj A pointer to the SFX singleton.
*/ */
void* SFXManager::mainLoop(void *obj) void SFXManager::mainLoop(void *obj)
{ {
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound) if (!UserConfigParams::m_enable_sound)
return NULL; return;
VS::setThreadName("SFXManager"); VS::setThreadName("SFXManager");
SFXManager *me = (SFXManager*)obj; SFXManager *me = (SFXManager*)obj;
me->m_sfx_commands.lock(); std::unique_lock<std::mutex> ul = me->m_sfx_commands.acquireMutex();
// Wait till we have an empty sfx in the queue // Wait till we have an empty sfx in the queue
while (me->m_sfx_commands.getData().empty() || while (me->m_sfx_commands.getData().empty() ||
@ -384,7 +362,7 @@ void* SFXManager::mainLoop(void *obj)
// (pthread_cond_wait man page)! // (pthread_cond_wait man page)!
while (empty) while (empty)
{ {
pthread_cond_wait(&me->m_cond_request, me->m_sfx_commands.getMutex()); me->m_condition_variable.wait(ul);
empty = me->m_sfx_commands.getData().empty(); empty = me->m_sfx_commands.getData().empty();
} }
SFXCommand *current = me->m_sfx_commands.getData().front(); SFXCommand *current = me->m_sfx_commands.getData().front();
@ -395,7 +373,7 @@ void* SFXManager::mainLoop(void *obj)
delete current; delete current;
break; break;
} }
me->m_sfx_commands.unlock(); ul.unlock();
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("Execute", 0, 255, 0); PROFILER_PUSH_CPU_MARKER("Execute", 0, 255, 0);
switch (current->m_command) switch (current->m_command)
@ -473,7 +451,7 @@ void* SFXManager::mainLoop(void *obj)
t = StkTime::getMonoTimeMs() - t; t = StkTime::getMonoTimeMs() - t;
me->queue(SFX_UPDATE, (SFXBase*)NULL, float(t / 1000.0)); me->queue(SFX_UPDATE, (SFXBase*)NULL, float(t / 1000.0));
} }
me->m_sfx_commands.lock(); ul = me->m_sfx_commands.acquireMutex();
PROFILER_POP_CPU_MARKER(); PROFILER_POP_CPU_MARKER();
} // while } // while
@ -488,9 +466,8 @@ void* SFXManager::mainLoop(void *obj)
delete me->m_sfx_commands.getData().front(); delete me->m_sfx_commands.getData().front();
me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin()); me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
} }
me->m_sfx_commands.unlock();
#endif #endif
return NULL; return;
} // mainLoop } // mainLoop
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -812,7 +789,7 @@ void SFXManager::update()
queue(SFX_UPDATE, (SFXBase*)NULL); queue(SFX_UPDATE, (SFXBase*)NULL);
// Wake up the sfx thread to handle all queued up audio commands. // Wake up the sfx thread to handle all queued up audio commands.
pthread_cond_signal(&m_cond_request); m_condition_variable.notify_one();
#endif #endif
} // update } // update
@ -1088,7 +1065,7 @@ SFXBase* SFXManager::quickSound(const std::string &sound_type)
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
if (!sfxAllowed()) return NULL; if (!sfxAllowed()) return NULL;
MutexLockerHelper lock(m_quick_sounds); std::unique_lock<std::mutex> ul = m_quick_sounds.acquireMutex();
std::map<std::string, SFXBase*>::iterator sound = std::map<std::string, SFXBase*>::iterator sound =
m_quick_sounds.getData().find(sound_type); m_quick_sounds.getData().find(sound_type);

View File

@ -25,8 +25,11 @@
#include "utils/synchronised.hpp" #include "utils/synchronised.hpp"
#include "utils/vec3.hpp" #include "utils/vec3.hpp"
#include <condition_variable>
#include <map> #include <map>
#include <string> #include <string>
#include <thread>
#include <vector> #include <vector>
#ifdef ENABLE_SOUND #ifdef ENABLE_SOUND
@ -219,18 +222,18 @@ private:
float m_master_gain; float m_master_gain;
/** Thread id of the thread running in this object. */ /** Thread id of the thread running in this object. */
Synchronised<pthread_t *> m_thread_id; std::thread m_thread;
uint64_t m_last_update_time; uint64_t m_last_update_time;
/** A conditional variable to wake up the main loop. */ /** A conditional variable to wake up the main loop. */
pthread_cond_t m_cond_request; std::condition_variable m_condition_variable;
void loadSfx(); void loadSfx();
SFXManager(); SFXManager();
virtual ~SFXManager(); virtual ~SFXManager();
static void* mainLoop(void *obj); static void mainLoop(void *obj);
void deleteSFX(SFXBase *sfx); void deleteSFX(SFXBase *sfx);
void queueCommand(SFXCommand *command); void queueCommand(SFXCommand *command);
void reallyPositionListenerNow(); void reallyPositionListenerNow();

View File

@ -41,11 +41,9 @@
# include <sys/socket.h> # include <sys/socket.h>
#endif #endif
#include <pthread.h>
#include <signal.h> #include <signal.h>
Synchronised<FILE*>Network::m_log_file = NULL; Synchronised<FILE*>Network::m_log_file;
bool Network::m_connection_debug = false; bool Network::m_connection_debug = false;
// ============================================================================ // ============================================================================

View File

@ -25,6 +25,7 @@
#include "states_screens/state_manager.hpp" #include "states_screens/state_manager.hpp"
#include "utils/vs.hpp" #include "utils/vs.hpp"
#include <functional>
#include <iostream> #include <iostream>
#include <stdio.h> #include <stdio.h>
#include <memory.h> #include <memory.h>
@ -74,18 +75,13 @@ namespace Online
m_game_polling_interval = 60; // same for game polling m_game_polling_interval = 60; // same for game polling
m_time_since_poll = m_menu_polling_interval; m_time_since_poll = m_menu_polling_interval;
curl_global_init(CURL_GLOBAL_DEFAULT); curl_global_init(CURL_GLOBAL_DEFAULT);
pthread_cond_init(&m_cond_request, NULL);
m_abort.setAtomic(false); m_abort.setAtomic(false);
} // RequestManager } // RequestManager
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
RequestManager::~RequestManager() RequestManager::~RequestManager()
{ {
m_thread_id.lock(); m_thread.join();
pthread_join(*m_thread_id.getData(), NULL);
delete m_thread_id.getData();
m_thread_id.unlock();
pthread_cond_destroy(&m_cond_request);
curl_global_cleanup(); curl_global_cleanup();
} // ~RequestManager } // ~RequestManager
@ -101,24 +97,7 @@ namespace Online
*/ */
void RequestManager::startNetworkThread() void RequestManager::startNetworkThread()
{ {
pthread_attr_t attr; m_thread = std::thread(std::bind(mainLoop, this));
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
m_thread_id.setAtomic(new pthread_t());
int error = pthread_create(m_thread_id.getData(), &attr,
&RequestManager::mainLoop, this);
if (error)
{
m_thread_id.lock();
delete m_thread_id.getData();
m_thread_id.unlock();
m_thread_id.setAtomic(0);
Log::error("HTTP Manager", "Could not create thread, error=%d.",
errno);
}
pthread_attr_destroy(&attr);
// In case that login id was not saved (or first start of stk), // In case that login id was not saved (or first start of stk),
// current player would not be defined at this stage. // current player would not be defined at this stage.
PlayerProfile *player = PlayerManager::getCurrentPlayer(); PlayerProfile *player = PlayerManager::getCurrentPlayer();
@ -181,7 +160,7 @@ namespace Online
m_request_queue.getData().push(request); m_request_queue.getData().push(request);
// Wake up the network http thread // Wake up the network http thread
pthread_cond_signal(&m_cond_request); m_condition_variable.notify_one();
m_request_queue.unlock(); m_request_queue.unlock();
} // addRequest } // addRequest
@ -191,13 +170,13 @@ namespace Online
* of packages to download, it will wait for commands to be issued. * of packages to download, it will wait for commands to be issued.
* \param obj: A pointer to this object, passed on by pthread_create * \param obj: A pointer to this object, passed on by pthread_create
*/ */
void *RequestManager::mainLoop(void *obj) void RequestManager::mainLoop(void *obj)
{ {
VS::setThreadName("RequestManager"); VS::setThreadName("RequestManager");
RequestManager *me = (RequestManager*) obj; RequestManager *me = (RequestManager*) obj;
me->m_current_request = nullptr; me->m_current_request = nullptr;
me->m_request_queue.lock(); std::unique_lock<std::mutex> ul = me->m_request_queue.acquireMutex();
while (me->m_request_queue.getData().empty() || while (me->m_request_queue.getData().empty() ||
me->m_request_queue.getData().top()->getType() != Request::RT_QUIT) me->m_request_queue.getData().top()->getType() != Request::RT_QUIT)
{ {
@ -208,7 +187,7 @@ namespace Online
// (pthread_cond_wait man page)! // (pthread_cond_wait man page)!
while (empty) while (empty)
{ {
pthread_cond_wait(&me->m_cond_request, me->m_request_queue.getMutex()); me->m_condition_variable.wait(ul);
empty = me->m_request_queue.getData().empty(); empty = me->m_request_queue.getData().empty();
} }
// We pause the request manager thread when going into background in iOS // We pause the request manager thread when going into background in iOS
@ -223,14 +202,14 @@ namespace Online
break; break;
} }
me->m_request_queue.unlock(); ul.unlock();
me->m_current_request->execute(); me->m_current_request->execute();
// This test is necessary in case that execute() was aborted // This test is necessary in case that execute() was aborted
// (otherwise the assert in addResult will be triggered). // (otherwise the assert in addResult will be triggered).
if (!me->getAbort()) if (!me->getAbort())
me->addResult(me->m_current_request); me->addResult(me->m_current_request);
me->m_current_request = nullptr; me->m_current_request = nullptr;
me->m_request_queue.lock(); ul = me->m_request_queue.acquireMutex();
} // while handle all requests } // while handle all requests
// Signal that the request manager can now be deleted. // Signal that the request manager can now be deleted.
@ -243,10 +222,6 @@ namespace Online
{ {
me->m_request_queue.getData().pop(); me->m_request_queue.getData().pop();
} }
me->m_request_queue.unlock();
pthread_exit(NULL);
return 0;
} // mainLoop } // mainLoop
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -34,10 +34,11 @@
#endif #endif
#include <atomic> #include <atomic>
#include <condition_variable>
#include <curl/curl.h> #include <curl/curl.h>
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <pthread.h> #include <thread>
namespace Online namespace Online
{ {
@ -99,7 +100,7 @@ namespace Online
std::shared_ptr<Online::Request> m_current_request; std::shared_ptr<Online::Request> m_current_request;
/** A conditional variable to wake up the main loop. */ /** A conditional variable to wake up the main loop. */
pthread_cond_t m_cond_request; std::condition_variable m_condition_variable;
/** Signal an abort in case that a download is still happening. */ /** Signal an abort in case that a download is still happening. */
Synchronised<bool> m_abort; Synchronised<bool> m_abort;
@ -114,7 +115,7 @@ namespace Online
float m_menu_polling_interval; float m_menu_polling_interval;
/** Thread id of the thread running in this object. */ /** Thread id of the thread running in this object. */
Synchronised<pthread_t *> m_thread_id; std::thread m_thread;
/** The list of pointers to all requests that still need to be /** The list of pointers to all requests that still need to be
* handled. */ * handled. */
@ -133,7 +134,7 @@ namespace Online
void addResult(std::shared_ptr<Online::Request> request); void addResult(std::shared_ptr<Online::Request> request);
void handleResultQueue(); void handleResultQueue();
static void *mainLoop(void *obj); static void mainLoop(void *obj);
RequestManager(); //const std::string &url RequestManager(); //const std::string &url
~RequestManager(); ~RequestManager();

View File

@ -18,8 +18,6 @@
#include "states_screens/dialogs/addons_loading.hpp" #include "states_screens/dialogs/addons_loading.hpp"
#include <pthread.h>
#include "addons/addons_manager.hpp" #include "addons/addons_manager.hpp"
#include "config/player_manager.hpp" #include "config/player_manager.hpp"
#include "config/user_config.hpp" #include "config/user_config.hpp"

View File

@ -19,24 +19,16 @@
#ifndef HEADER_SYNCHRONISED_HPP #ifndef HEADER_SYNCHRONISED_HPP
#define HEADER_SYNCHRONISED_HPP #define HEADER_SYNCHRONISED_HPP
#include <pthread.h> #include <mutex>
class ISynchronised
{
public :
virtual ~ISynchronised() {}
virtual void lock() const = 0 ;
virtual void unlock() const = 0;
};
/** A variable that is automatically synchronised using pthreads mutex. /** A variable that is automatically synchronised using pthreads mutex.
*/ */
template<typename TYPE> template<typename TYPE>
class Synchronised : public ISynchronised class Synchronised
{ {
private: private:
/** The mutex to protect this variable with. */ /** The mutex to protect this variable with. */
mutable pthread_mutex_t m_mutex; mutable std::mutex m_mutex;
/** The actual data to be used. */ /** The actual data to be used. */
TYPE m_data; TYPE m_data;
public: public:
@ -44,7 +36,6 @@ public:
/** Initialise the data and the mutex with default constructors. */ /** Initialise the data and the mutex with default constructors. */
Synchronised() : m_data() Synchronised() : m_data()
{ {
pthread_mutex_init(&m_mutex, NULL);
} // Synchronised() } // Synchronised()
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -52,7 +43,6 @@ public:
Synchronised(const TYPE &v) Synchronised(const TYPE &v)
{ {
m_data = v; m_data = v;
pthread_mutex_init(&m_mutex, NULL);
} // Synchronised } // Synchronised
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -60,7 +50,6 @@ public:
*/ */
~Synchronised() ~Synchronised()
{ {
pthread_mutex_destroy(&m_mutex);
} // ~Synchronised } // ~Synchronised
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -69,9 +58,8 @@ public:
*/ */
void setAtomic(const TYPE &v) void setAtomic(const TYPE &v)
{ {
pthread_mutex_lock(&m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
m_data = v; m_data = v;
pthread_mutex_unlock(&m_mutex);
} // set } // set
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -80,9 +68,9 @@ public:
TYPE getAtomic() const TYPE getAtomic() const
{ {
TYPE v; TYPE v;
pthread_mutex_lock(&m_mutex); std::unique_lock<std::mutex> ul(m_mutex);
v = m_data; v = m_data;
pthread_mutex_unlock(&m_mutex); ul.unlock();
return v; return v;
} // get } // get
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -104,37 +92,20 @@ public:
/** Locks the mutex. Note that calls to get() or set() will fail, since /** Locks the mutex. Note that calls to get() or set() will fail, since
* they will try to lock the mutex as well! * they will try to lock the mutex as well!
*/ */
void lock() const { pthread_mutex_lock(&m_mutex); } void lock() const { m_mutex.lock(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Unlocks the mutex. /** Unlocks the mutex.
*/ */
void unlock() const {pthread_mutex_unlock(&m_mutex); } void unlock() const { m_mutex.unlock(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Gives access to the mutex, which can then be used in other pthread /** Gives unique_lock to the mutex, which can then be used by
* calls (e.g. pthread_cond_wait). * std::condition_variable wait. */
*/ std::unique_lock<std::mutex> acquireMutex() const
pthread_mutex_t* getMutex() { return &m_mutex; } { return std::unique_lock<std::mutex>(m_mutex); }
private: private:
// Make sure that no actual copying is taking place // Make sure that no actual copying is taking place
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void operator=(const Synchronised<TYPE>& v) {} void operator=(const Synchronised<TYPE>& v) {}
}; };
#define MutexLocker(x) MutexLockerHelper __dummy(x);
class MutexLockerHelper
{
const ISynchronised * m_synchronised;
public:
MutexLockerHelper(const ISynchronised & synchronised){
m_synchronised = &synchronised;
m_synchronised->lock();
}
~MutexLockerHelper(){
m_synchronised->unlock();
}
};
#endif #endif