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/vs.hpp"
#include <pthread.h>
#include <stdexcept>
#include <algorithm>
#include <map>
#include <functional>
#include <stdio.h>
#include <stdlib.h>
#include <limits>
@ -91,28 +92,9 @@ SFXManager::SFXManager()
#ifdef 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
// (since the user might enable it later).
int error = pthread_create(m_thread_id.getData(), &attr,
&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);
m_thread = std::thread(std::bind(mainLoop, this));
setMasterSFXVolume( UserConfigParams::m_sfx_volume );
m_sfx_commands.lock();
m_sfx_commands.getData().clear();
@ -129,11 +111,7 @@ SFXManager::~SFXManager()
#ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound)
{
m_thread_id.lock();
pthread_join(*m_thread_id.getData(), NULL);
delete m_thread_id.getData();
m_thread_id.unlock();
pthread_cond_destroy(&m_cond_request);
m_thread.join();
}
#endif
@ -346,7 +324,7 @@ void SFXManager::stopThread()
{
queue(SFX_EXIT);
// Make sure the thread wakes up.
pthread_cond_signal(&m_cond_request);
m_condition_variable.notify_one();
}
else
#endif
@ -361,16 +339,16 @@ void SFXManager::stopThread()
* in order to avoid rendering delays.
* \param obj A pointer to the SFX singleton.
*/
void* SFXManager::mainLoop(void *obj)
void SFXManager::mainLoop(void *obj)
{
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return NULL;
return;
VS::setThreadName("SFXManager");
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
while (me->m_sfx_commands.getData().empty() ||
@ -384,7 +362,7 @@ void* SFXManager::mainLoop(void *obj)
// (pthread_cond_wait man page)!
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();
}
SFXCommand *current = me->m_sfx_commands.getData().front();
@ -395,7 +373,7 @@ void* SFXManager::mainLoop(void *obj)
delete current;
break;
}
me->m_sfx_commands.unlock();
ul.unlock();
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("Execute", 0, 255, 0);
switch (current->m_command)
@ -473,7 +451,7 @@ void* SFXManager::mainLoop(void *obj)
t = StkTime::getMonoTimeMs() - t;
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();
} // while
@ -488,9 +466,8 @@ void* SFXManager::mainLoop(void *obj)
delete me->m_sfx_commands.getData().front();
me->m_sfx_commands.getData().erase(me->m_sfx_commands.getData().begin());
}
me->m_sfx_commands.unlock();
#endif
return NULL;
return;
} // mainLoop
//----------------------------------------------------------------------------
@ -812,7 +789,7 @@ void SFXManager::update()
queue(SFX_UPDATE, (SFXBase*)NULL);
// Wake up the sfx thread to handle all queued up audio commands.
pthread_cond_signal(&m_cond_request);
m_condition_variable.notify_one();
#endif
} // update
@ -1088,7 +1065,7 @@ SFXBase* SFXManager::quickSound(const std::string &sound_type)
#ifdef ENABLE_SOUND
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 =
m_quick_sounds.getData().find(sound_type);

View File

@ -25,8 +25,11 @@
#include "utils/synchronised.hpp"
#include "utils/vec3.hpp"
#include <condition_variable>
#include <map>
#include <string>
#include <thread>
#include <vector>
#ifdef ENABLE_SOUND
@ -219,18 +222,18 @@ private:
float m_master_gain;
/** 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;
/** A conditional variable to wake up the main loop. */
pthread_cond_t m_cond_request;
std::condition_variable m_condition_variable;
void loadSfx();
SFXManager();
virtual ~SFXManager();
static void* mainLoop(void *obj);
static void mainLoop(void *obj);
void deleteSFX(SFXBase *sfx);
void queueCommand(SFXCommand *command);
void reallyPositionListenerNow();

View File

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

View File

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

View File

@ -34,10 +34,11 @@
#endif
#include <atomic>
#include <condition_variable>
#include <curl/curl.h>
#include <memory>
#include <queue>
#include <pthread.h>
#include <thread>
namespace Online
{
@ -99,7 +100,7 @@ namespace Online
std::shared_ptr<Online::Request> m_current_request;
/** 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. */
Synchronised<bool> m_abort;
@ -114,7 +115,7 @@ namespace Online
float m_menu_polling_interval;
/** 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
* handled. */
@ -133,7 +134,7 @@ namespace Online
void addResult(std::shared_ptr<Online::Request> request);
void handleResultQueue();
static void *mainLoop(void *obj);
static void mainLoop(void *obj);
RequestManager(); //const std::string &url
~RequestManager();

View File

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

View File

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