Use C++11 threads

This commit is contained in:
Tamás Bálint Misius
2019-04-17 00:23:57 +02:00
parent 9d92b77163
commit 2e76b10619
20 changed files with 230 additions and 375 deletions

View File

@@ -21,8 +21,6 @@ namespace http
post_fields_last(NULL)
#endif
{
pthread_cond_init(&done_cv, NULL);
pthread_mutex_init(&rm_mutex, NULL);
easy = curl_easy_init();
RequestManager::Ref().AddRequest(this);
}
@@ -36,8 +34,6 @@ namespace http
curl_formfree(post_fields_first);
#endif
curl_slist_free_all(headers);
pthread_mutex_destroy(&rm_mutex);
pthread_cond_destroy(&done_cv);
}
void Request::AddHeader(ByteString name, ByteString value)
@@ -179,9 +175,10 @@ namespace http
curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, Request::WriteDataHandler);
}
pthread_mutex_lock(&rm_mutex);
rm_started = true;
pthread_mutex_unlock(&rm_mutex);
{
std::lock_guard<std::mutex> g(rm_mutex);
rm_started = true;
}
RequestManager::Ref().StartRequest(this);
}
@@ -194,19 +191,18 @@ namespace http
return ""; // shouldn't happen but just in case
}
pthread_mutex_lock(&rm_mutex);
while (!rm_finished)
ByteString response_out;
{
pthread_cond_wait(&done_cv, &rm_mutex);
std::unique_lock<std::mutex> l(rm_mutex);
done_cv.wait(l, [this]() { return rm_finished; });
rm_started = false;
rm_canceled = true;
if (status_out)
{
*status_out = status;
}
response_out = std::move(response_body);
}
rm_started = false;
rm_canceled = true;
if (status_out)
{
*status_out = status;
}
ByteString response_out = std::move(response_body);
pthread_mutex_unlock(&rm_mutex);
RequestManager::Ref().RemoveRequest(this);
return response_out;
@@ -214,7 +210,7 @@ namespace http
void Request::CheckProgress(int *total, int *done)
{
pthread_mutex_lock(&rm_mutex);
std::lock_guard<std::mutex> g(rm_mutex);
if (total)
{
*total = rm_total;
@@ -223,43 +219,37 @@ namespace http
{
*done = rm_done;
}
pthread_mutex_unlock(&rm_mutex);
}
// returns true if the request has finished
bool Request::CheckDone()
{
pthread_mutex_lock(&rm_mutex);
bool ret = rm_finished;
pthread_mutex_unlock(&rm_mutex);
return ret;
std::lock_guard<std::mutex> g(rm_mutex);
return rm_finished;
}
// returns true if the request was canceled
bool Request::CheckCanceled()
{
pthread_mutex_lock(&rm_mutex);
bool ret = rm_canceled;
pthread_mutex_unlock(&rm_mutex);
return ret;
std::lock_guard<std::mutex> g(rm_mutex);
return rm_canceled;
}
// returns true if the request is running
bool Request::CheckStarted()
{
pthread_mutex_lock(&rm_mutex);
bool ret = rm_started;
pthread_mutex_unlock(&rm_mutex);
return ret;
std::lock_guard<std::mutex> g(rm_mutex);
return rm_started;
}
// cancels the request, the request thread will delete the Request* when it finishes (do not use Request in any way after canceling)
void Request::Cancel()
{
pthread_mutex_lock(&rm_mutex);
rm_canceled = true;
pthread_mutex_unlock(&rm_mutex);
{
std::lock_guard<std::mutex> g(rm_mutex);
rm_canceled = true;
}
RequestManager::Ref().RemoveRequest(this);
}

View File

@@ -3,10 +3,10 @@
#include <map>
#include "common/tpt-minmax.h" // for MSVC, ensures windows.h doesn't cause compile errors by defining min/max
#include "common/tpt-thread.h"
#include <mutex>
#include <condition_variable>
#include <curl/curl.h>
#include "common/String.h"
#undef GetUserName // pthreads defines this, breaks stuff
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 55, 0)
# define REQUEST_USE_CURL_OFFSET_T
@@ -32,7 +32,7 @@ namespace http
volatile bool rm_finished;
volatile bool rm_canceled;
volatile bool rm_started;
pthread_mutex_t rm_mutex;
std::mutex rm_mutex;
bool added_to_multi;
int status;
@@ -46,7 +46,7 @@ namespace http
std::map<ByteString, ByteString> post_fields_map;
#endif
pthread_cond_t done_cv;
std::condition_variable done_cv;
static size_t WriteDataHandler(char * ptr, size_t size, size_t count, void * userdata);

View File

@@ -21,36 +21,27 @@ namespace http
rt_shutting_down(false),
multi(NULL)
{
pthread_cond_init(&rt_cv, NULL);
pthread_mutex_init(&rt_mutex, NULL);
}
RequestManager::~RequestManager()
{
pthread_mutex_destroy(&rt_mutex);
pthread_cond_destroy(&rt_cv);
}
void RequestManager::Shutdown()
{
pthread_mutex_lock(&rt_mutex);
rt_shutting_down = true;
pthread_cond_signal(&rt_cv);
pthread_mutex_unlock(&rt_mutex);
{
std::lock_guard<std::mutex> g(rt_mutex);
rt_shutting_down = true;
}
rt_cv.notify_one();
pthread_join(worker_thread, NULL);
worker_thread.join();
curl_multi_cleanup(multi);
multi = NULL;
curl_global_cleanup();
}
TH_ENTRY_POINT void *RequestManager::RequestManagerHelper(void *obj)
{
((RequestManager *)obj)->Worker();
return NULL;
}
void RequestManager::Initialise(ByteString Proxy)
{
curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -64,7 +55,7 @@ namespace http
user_agent = ByteString::Build("PowderToy/", SAVE_VERSION, ".", MINOR_VERSION, " (", IDENT_PLATFORM, "; ", IDENT_BUILD, "; M", MOD_ID, ") TPTPP/", SAVE_VERSION, ".", MINOR_VERSION, ".", BUILD_NUM, IDENT_RELTYPE, ".", SNAPSHOT_ID);
pthread_create(&worker_thread, NULL, &RequestManager::RequestManagerHelper, this);
worker_thread = std::thread([this]() { Worker(); });
}
void RequestManager::Worker()
@@ -72,24 +63,25 @@ namespace http
bool shutting_down = false;
while (!shutting_down)
{
pthread_mutex_lock(&rt_mutex);
if (!requests_added_to_multi)
{
while (!rt_shutting_down && requests_to_add.empty() && !requests_to_start && !requests_to_remove)
std::unique_lock<std::mutex> l(rt_mutex);
if (!requests_added_to_multi)
{
pthread_cond_wait(&rt_cv, &rt_mutex);
while (!rt_shutting_down && requests_to_add.empty() && !requests_to_start && !requests_to_remove)
{
rt_cv.wait(l);
}
}
shutting_down = rt_shutting_down;
requests_to_remove = false;
requests_to_start = false;
for (Request *request : requests_to_add)
{
request->status = 0;
requests.insert(request);
}
requests_to_add.clear();
}
shutting_down = rt_shutting_down;
requests_to_remove = false;
requests_to_start = false;
for (Request *request : requests_to_add)
{
request->status = 0;
requests.insert(request);
}
requests_to_add.clear();
pthread_mutex_unlock(&rt_mutex);
if (multi && requests_added_to_multi)
{
@@ -157,52 +149,60 @@ namespace http
std::set<Request *> requests_to_remove;
for (Request *request : requests)
{
pthread_mutex_lock(&request->rm_mutex);
if (shutting_down)
bool signal_done = false;
{
// In the weird case that a http::Request::Simple* call is
// waiting on this Request, we should fail the request
// instead of cancelling it ourselves.
request->status = 610;
}
if (!request->rm_canceled && request->rm_started && !request->added_to_multi && !request->status)
{
if (multi && request->easy)
std::lock_guard<std::mutex> g(request->rm_mutex);
if (shutting_down)
{
MultiAdd(request);
// In the weird case that a http::Request::Simple* call is
// waiting on this Request, we should fail the request
// instead of cancelling it ourselves.
request->status = 610;
}
else
if (!request->rm_canceled && request->rm_started && !request->added_to_multi && !request->status)
{
request->status = 604;
if (multi && request->easy)
{
MultiAdd(request);
}
else
{
request->status = 604;
}
}
}
if (!request->rm_canceled && request->rm_started && !request->rm_finished)
{
if (multi && request->easy)
if (!request->rm_canceled && request->rm_started && !request->rm_finished)
{
if (multi && request->easy)
{
#ifdef REQUEST_USE_CURL_OFFSET_T
curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &request->rm_total);
curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD_T, &request->rm_done);
curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &request->rm_total);
curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD_T, &request->rm_done);
#else
double total, done;
curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &total);
curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD, &done);
request->rm_total = (curl_off_t)total;
request->rm_done = (curl_off_t)done;
double total, done;
curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &total);
curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD, &done);
request->rm_total = (curl_off_t)total;
request->rm_done = (curl_off_t)done;
#endif
}
if (request->status)
{
request->rm_finished = true;
MultiRemove(request);
signal_done = true;
}
}
if (request->status)
if (request->rm_canceled)
{
request->rm_finished = true;
MultiRemove(request);
pthread_cond_signal(&request->done_cv);
requests_to_remove.insert(request);
}
}
if (request->rm_canceled)
if (signal_done)
{
requests_to_remove.insert(request);
request->done_cv.notify_one();
}
pthread_mutex_unlock(&request->rm_mutex);
}
for (Request *request : requests_to_remove)
{
@@ -235,25 +235,28 @@ namespace http
void RequestManager::AddRequest(Request *request)
{
pthread_mutex_lock(&rt_mutex);
requests_to_add.insert(request);
pthread_cond_signal(&rt_cv);
pthread_mutex_unlock(&rt_mutex);
{
std::lock_guard<std::mutex> g(rt_mutex);
requests_to_add.insert(request);
}
rt_cv.notify_one();
}
void RequestManager::StartRequest(Request *request)
{
pthread_mutex_lock(&rt_mutex);
requests_to_start = true;
pthread_cond_signal(&rt_cv);
pthread_mutex_unlock(&rt_mutex);
{
std::lock_guard<std::mutex> g(rt_mutex);
requests_to_start = true;
}
rt_cv.notify_one();
}
void RequestManager::RemoveRequest(Request *request)
{
pthread_mutex_lock(&rt_mutex);
requests_to_remove = true;
pthread_cond_signal(&rt_cv);
pthread_mutex_unlock(&rt_mutex);
{
std::lock_guard<std::mutex> g(rt_mutex);
requests_to_remove = true;
}
rt_cv.notify_one();
}
}

View File

@@ -2,20 +2,21 @@
#define REQUESTMANAGER_H
#include "common/tpt-minmax.h" // for MSVC, ensures windows.h doesn't cause compile errors by defining min/max
#include "common/tpt-thread.h"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <ctime>
#include <set>
#include <curl/curl.h>
#include "common/Singleton.h"
#include "common/String.h"
#undef GetUserName // pthreads (included by curl) defines this, breaks stuff
namespace http
{
class Request;
class RequestManager : public Singleton<RequestManager>
{
pthread_t worker_thread;
std::thread worker_thread;
std::set<Request *> requests;
int requests_added_to_multi;
@@ -23,8 +24,8 @@ namespace http
bool requests_to_start;
bool requests_to_remove;
bool rt_shutting_down;
pthread_mutex_t rt_mutex;
pthread_cond_t rt_cv;
std::mutex rt_mutex;
std::condition_variable rt_cv;
CURLM *multi;
@@ -36,8 +37,6 @@ namespace http
void StartRequest(Request *request);
void RemoveRequest(Request *request);
static TH_ENTRY_POINT void *RequestManagerHelper(void *obj);
public:
RequestManager();
~RequestManager();

View File

@@ -4,7 +4,6 @@
#include <limits>
#include <stdexcept>
#include "common/tpt-thread.h"
#include "String.h"
ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto)
@@ -374,31 +373,10 @@ struct LocaleImpl
}
};
static void destroyLocaleImpl(void *ptr)
{
delete static_cast<LocaleImpl *>(ptr);
}
static pthread_once_t localeOnce = PTHREAD_ONCE_INIT;
static pthread_key_t localeKey;
static void createLocaleKey()
{
if(int error = pthread_key_create(&localeKey, destroyLocaleImpl))
throw std::system_error(error, std::system_category(), "Could not create TLS key for LocaleImpl");
}
static LocaleImpl *getLocaleImpl()
{
pthread_once(&localeOnce, createLocaleKey);
void *ptr = pthread_getspecific(localeKey);
if(!ptr)
{
ptr = static_cast<void *>(new LocaleImpl());
if(int error = pthread_setspecific(localeKey, ptr))
throw std::system_error(error, std::system_category(), "Could not put LocaleImpl into TLS");
}
return static_cast<LocaleImpl *>(ptr);
thread_local LocaleImpl li;
return &li;
}
ByteString ByteStringBuilder::Build() const

View File

@@ -1,26 +0,0 @@
#ifndef TPT_THREAD_H
#define TPT_THREAD_H
#if defined(WIN) && defined(__GNUC__)
#define TH_ENTRY_POINT __attribute__((force_align_arg_pointer))
#define _TIMESPEC_DEFINED
#else
#define TH_ENTRY_POINT
#endif
// fix 'timespec' error in VS 2015
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
#define _TIMESPEC_DEFINED 1
#endif
#include <pthread.h>
#undef GetUserName
// Fix deprecation warnings with recent pthread versions on Windows
#if defined(_PTW32_STATIC_LIB) && defined(WIN)
#if PTW32_VERSION <= 2, 8, 0, 0
#define PTW32_STATIC_LIB
#endif
#endif
#endif

View File

@@ -128,9 +128,6 @@ public:
VideoBuffer DumpFrame();
void Acquire();
void Release();
void blendpixel(int x, int y, int r, int g, int b, int a);
void addpixel(int x, int y, int r, int g, int b, int a);

View File

@@ -1,22 +1,12 @@
#include "Graphics.h"
#include "FontReader.h"
#include "common/tpt-thread.h"
#ifdef OGLI
static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
//static pthread_mutex_t TMPMUT = PTHREAD_MUTEX_INITIALIZER;
Graphics::Graphics():
sdl_scale(1)
{
// if(gMutex == TMPMUT)
// pthread_mutex_init (&gMutex, NULL);
LoadDefaults();
InitialiseTextures();
//Texture for main UI
}
void Graphics::LoadDefaults()
@@ -68,16 +58,6 @@ void Graphics::DestroyTextures()
//Todo...
}
void Graphics::Acquire()
{
pthread_mutex_lock(&gMutex);
}
void Graphics::Release()
{
pthread_mutex_unlock(&gMutex);
}
Graphics::~Graphics()
{
}

View File

@@ -9,16 +9,6 @@ sdl_scale(1)
}
void Graphics::Acquire()
{
}
void Graphics::Release()
{
}
Graphics::~Graphics()
{
free(vid);

View File

@@ -225,7 +225,6 @@ void Engine::Draw()
{
if(lastBuffer && !(state_ && state_->Position.X == 0 && state_->Position.Y == 0 && state_->Size.X == width_ && state_->Size.Y == height_))
{
g->Acquire();
g->Clear();
#ifndef OGLI
memcpy(g->vid, lastBuffer, (width_ * height_) * PIXELSIZE);
@@ -242,7 +241,6 @@ void Engine::Draw()
state_->DoDraw();
g->Finalise();
g->Release();
FrameIndex++;
FrameIndex %= 7200;
}

View File

@@ -3,6 +3,8 @@
#include "client/Client.h"
#include <thread>
SearchModel::SearchModel():
loadedSave(NULL),
currentSort("best"),
@@ -14,8 +16,10 @@ SearchModel::SearchModel():
saveListLoaded(false),
updateSaveListWorking(false),
updateSaveListFinished(false),
updateSaveListResult(nullptr),
updateTagListWorking(false),
updateTagListFinished(false)
updateTagListFinished(false),
updateTagListResult(nullptr)
{
}
@@ -29,36 +33,26 @@ bool SearchModel::GetShowTags()
return showTags;
}
TH_ENTRY_POINT void * SearchModel::updateSaveListTHelper(void * obj)
{
return ((SearchModel *)obj)->updateSaveListT();
}
void * SearchModel::updateSaveListT()
void SearchModel::updateSaveListT()
{
ByteString category = "";
if(showFavourite)
category = "Favourites";
if(showOwn && Client::Ref().GetAuthUser().UserID)
category = "by:"+Client::Ref().GetAuthUser().Username;
vector<SaveInfo*> * saveList = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, thResultCount);
std::vector<SaveInfo*> * saveList = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, thResultCount);
updateSaveListResult = saveList;
updateSaveListFinished = true;
return saveList;
}
TH_ENTRY_POINT void * SearchModel::updateTagListTHelper(void * obj)
{
return ((SearchModel *)obj)->updateTagListT();
}
void * SearchModel::updateTagListT()
void SearchModel::updateTagListT()
{
int tagResultCount;
std::vector<std::pair<ByteString, int> > * tagList = Client::Ref().GetTags(0, 24, "", tagResultCount);
updateTagListResult = tagList;
updateTagListFinished = true;
return tagList;
}
bool SearchModel::UpdateSaveList(int pageNumber, String query)
@@ -88,12 +82,12 @@ bool SearchModel::UpdateSaveList(int pageNumber, String query)
{
updateTagListFinished = false;
updateTagListWorking = true;
pthread_create(&updateTagListThread, 0, &SearchModel::updateTagListTHelper, this);
std::thread([this]() { updateTagListT(); }).detach();
}
updateSaveListFinished = false;
updateSaveListWorking = true;
pthread_create(&updateSaveListThread, 0, &SearchModel::updateSaveListTHelper, this);
std::thread([this]() { updateSaveListT(); }).detach();
return true;
}
return false;
@@ -117,12 +111,12 @@ SaveInfo * SearchModel::GetLoadedSave(){
return loadedSave;
}
vector<SaveInfo*> SearchModel::GetSaveList()
std::vector<SaveInfo*> SearchModel::GetSaveList()
{
return saveList;
}
vector<pair<ByteString, int> > SearchModel::GetTagList()
std::vector<std::pair<ByteString, int> > SearchModel::GetTagList()
{
return tagList;
}
@@ -137,8 +131,8 @@ void SearchModel::Update()
lastError = "";
saveListLoaded = true;
vector<SaveInfo*> * tempSaveList;
pthread_join(updateSaveListThread, (void**)&tempSaveList);
std::vector<SaveInfo *> *tempSaveList = updateSaveListResult;
updateSaveListResult = nullptr;
if(tempSaveList)
{
@@ -164,8 +158,8 @@ void SearchModel::Update()
{
updateTagListWorking = false;
vector<pair<ByteString, int> > * tempTagList;
pthread_join(updateTagListThread, (void**)&tempTagList);
std::vector<std::pair<ByteString, int>> *tempTagList = updateTagListResult;
updateTagListResult = nullptr;
if(tempTagList)
{

View File

@@ -4,13 +4,11 @@
#include <vector>
#include "common/String.h"
#include "common/tpt-minmax.h"
#include "common/tpt-thread.h"
#include <atomic>
#include <cmath>
#include "client/SaveInfo.h"
#include "SearchView.h"
using namespace std;
class SearchView;
class SearchModel
{
@@ -19,10 +17,10 @@ private:
ByteString currentSort;
String lastQuery;
String lastError;
vector<int> selected;
vector<SearchView*> observers;
vector<SaveInfo*> saveList;
vector<pair<ByteString, int> > tagList;
std::vector<int> selected;
std::vector<SearchView*> observers;
std::vector<SaveInfo*> saveList;
std::vector<std::pair<ByteString, int> > tagList;
int currentPage;
int resultCount;
int thResultCount;
@@ -40,16 +38,14 @@ private:
//Variables and methods for background save request
bool saveListLoaded;
bool updateSaveListWorking;
volatile bool updateSaveListFinished;
pthread_t updateSaveListThread;
TH_ENTRY_POINT static void * updateSaveListTHelper(void * obj);
void * updateSaveListT();
std::atomic<bool> updateSaveListFinished;
void updateSaveListT();
std::vector<SaveInfo *> *updateSaveListResult;
bool updateTagListWorking;
volatile bool updateTagListFinished;
pthread_t updateTagListThread;
TH_ENTRY_POINT static void * updateTagListTHelper(void * obj);
void * updateTagListT();
std::atomic<bool> updateTagListFinished;
void updateTagListT();
std::vector<std::pair<ByteString, int>> *updateTagListResult;
public:
SearchModel();
virtual ~SearchModel();
@@ -58,8 +54,8 @@ public:
bool GetShowTags();
void AddObserver(SearchView * observer);
bool UpdateSaveList(int pageNumber, String query);
vector<SaveInfo*> GetSaveList();
vector<pair<ByteString, int> > GetTagList();
std::vector<SaveInfo*> GetSaveList();
std::vector<std::pair<ByteString, int> > GetTagList();
String GetLastError() { return lastError; }
int GetPageCount()
{
@@ -79,7 +75,7 @@ public:
void SetLoadedSave(SaveInfo * save);
SaveInfo * GetLoadedSave();
bool GetSavesLoaded() { return saveListLoaded; }
vector<int> GetSelected() { return selected; }
std::vector<int> GetSelected() { return selected; }
void ClearSelected() { selected.clear(); notifySelectedChanged(); }
void SelectSave(int saveID);
void DeselectSave(int saveID);

View File

@@ -1,6 +1,5 @@
#include <cmath>
#include <sys/types.h>
#include "common/tpt-thread.h"
#include "Config.h"
#include "Gravity.h"
#include "Misc.h"
@@ -85,13 +84,15 @@ void Gravity::gravity_update_async()
int result;
if (ngrav_enable)
{
if (!pthread_mutex_trylock(&gravmutex))
bool signal_grav = false;
{
result = grav_ready;
if (result) //Did the gravity thread finish?
std::unique_lock<std::mutex> l(gravmutex, std::defer_lock);
if (l.try_lock())
{
//if (!sys_pause||framerender){ //Only update if not paused
//Switch the full size gravmaps, we don't really need the two above any more
result = grav_ready;
if (result) //Did the gravity thread finish?
{
float *tmpf;
if (th_gravchanged && !ignoreNextResult)
@@ -121,10 +122,14 @@ void Gravity::gravity_update_async()
th_gravmap = tmpf;
grav_ready = 0; //Tell the other thread that we're ready for it to continue
pthread_cond_signal(&gravcv);
//}
signal_grav = true;
}
}
if (signal_grav)
{
gravcv.notify_one();
}
pthread_mutex_unlock(&gravmutex);
}
//Apply the gravity mask
membwand(gravy, gravmask, (XRES/CELL)*(YRES/CELL)*sizeof(float), (XRES/CELL)*(YRES/CELL)*sizeof(unsigned));
@@ -133,12 +138,6 @@ void Gravity::gravity_update_async()
}
}
TH_ENTRY_POINT void *Gravity::update_grav_async_helper(void * context)
{
((Gravity *)context)->update_grav_async();
return NULL;
}
void Gravity::update_grav_async()
{
int done = 0;
@@ -155,7 +154,8 @@ void Gravity::update_grav_async()
if (!grav_fft_status)
grav_fft_init();
#endif
pthread_mutex_lock(&gravmutex);
std::unique_lock<std::mutex> l(gravmutex);
while (!thread_done)
{
if (!done)
@@ -167,13 +167,11 @@ void Gravity::update_grav_async()
thread_done = gravthread_done;
} else {
// wait for main thread
pthread_cond_wait(&gravcv, &gravmutex);
gravcv.wait(l);
done = grav_ready;
thread_done = gravthread_done;
}
}
pthread_mutex_unlock(&gravmutex);
pthread_exit(NULL);
}
void Gravity::start_grav_async()
@@ -183,9 +181,7 @@ void Gravity::start_grav_async()
gravthread_done = 0;
grav_ready = 0;
pthread_mutex_init (&gravmutex, NULL);
pthread_cond_init(&gravcv, NULL);
pthread_create(&gravthread, NULL, &Gravity::update_grav_async_helper, this); //Start asynchronous gravity simulation
gravthread = std::thread([this]() { update_grav_async(); }); //Start asynchronous gravity simulation
ngrav_enable = 1;
memset(gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
@@ -198,12 +194,12 @@ void Gravity::stop_grav_async()
{
if (ngrav_enable)
{
pthread_mutex_lock(&gravmutex);
gravthread_done = 1;
pthread_cond_signal(&gravcv);
pthread_mutex_unlock(&gravmutex);
pthread_join(gravthread, NULL);
pthread_mutex_destroy(&gravmutex); //Destroy the mutex
{
std::lock_guard<std::mutex> g(gravmutex);
gravthread_done = 1;
}
gravcv.notify_one();
gravthread.join();
ngrav_enable = 0;
}
//Clear the grav velocities

View File

@@ -1,7 +1,9 @@
#ifndef GRAVITY_H
#define GRAVITY_H
#include "common/tpt-thread.h"
#include <thread>
#include <mutex>
#include <condition_variable>
#include "Config.h"
#include "Simulation.h"
@@ -18,28 +20,6 @@ struct mask_el {
};
typedef struct mask_el mask_el;
/*
* float *gravmap = NULL;//Maps to be used by the main thread
float *gravp = NULL;
float *gravy = NULL;
float *gravx = NULL;
unsigned *gravmask = NULL;
float *th_ogravmap = NULL;// Maps to be processed by the gravity thread
float *th_gravmap = NULL;
float *th_gravx = NULL;
float *th_gravy = NULL;
float *th_gravp = NULL;
int th_gravchanged = 0;
pthread_t gravthread;
pthread_mutex_t gravmutex;
pthread_cond_t gravcv;
int grav_ready = 0;
int gravthread_done = 0;
*/
class Gravity
{
private:
@@ -52,9 +32,9 @@ private:
int th_gravchanged;
pthread_t gravthread;
pthread_mutex_t gravmutex;
pthread_cond_t gravcv;
std::thread gravthread;
std::mutex gravmutex;
std::condition_variable gravcv;
int grav_ready;
int gravthread_done;
@@ -84,7 +64,6 @@ public:
void gravity_cleanup();
void gravity_update_async();
TH_ENTRY_POINT static void *update_grav_async_helper(void * context);
void update_grav_async();
void start_grav_async();

View File

@@ -29,13 +29,11 @@ SaveRenderer::SaveRenderer(){
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Reset framebuffer binding
glDisable(GL_TEXTURE_2D);
#endif
pthread_mutex_init(&renderMutex, NULL);
}
VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
{
pthread_mutex_lock(&renderMutex);
std::lock_guard<std::mutex> gx(renderMutex);
int width, height;
VideoBuffer * tempThumb = NULL;
@@ -43,7 +41,6 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
height = save->blockHeight;
bool doCollapse = save->Collapsed();
g->Acquire();
g->Clear();
sim->clear_sim();
@@ -148,15 +145,13 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
}
if(doCollapse)
save->Collapse();
g->Release();
pthread_mutex_unlock(&renderMutex);
return tempThumb;
}
VideoBuffer * SaveRenderer::Render(unsigned char * saveData, int dataSize, bool decorations, bool fire)
{
pthread_mutex_lock(&renderMutex);
std::lock_guard<std::mutex> g(renderMutex);
GameSave * tempSave;
try {
@@ -167,17 +162,15 @@ VideoBuffer * SaveRenderer::Render(unsigned char * saveData, int dataSize, bool
VideoBuffer * buffer = new VideoBuffer(64, 64);
buffer->BlendCharacter(32, 32, 'x', 255, 255, 255, 255);
pthread_mutex_unlock(&renderMutex);
return buffer;
}
VideoBuffer * thumb = Render(tempSave, decorations, fire);
delete tempSave;
pthread_mutex_unlock(&renderMutex);
return thumb;
}
SaveRenderer::~SaveRenderer() {
pthread_mutex_destroy(&renderMutex);
SaveRenderer::~SaveRenderer()
{
}

View File

@@ -4,7 +4,7 @@
#include "graphics/OpenGLHeaders.h"
#endif
#include "common/Singleton.h"
#include "common/tpt-thread.h"
#include <mutex>
class GameSave;
class VideoBuffer;
@@ -16,7 +16,7 @@ class SaveRenderer: public Singleton<SaveRenderer> {
Graphics * g;
Simulation * sim;
Renderer * ren;
pthread_mutex_t renderMutex;
std::mutex renderMutex;
public:
SaveRenderer();
VideoBuffer * Render(GameSave * save, bool decorations = true, bool fire = true);

View File

@@ -5,11 +5,13 @@
void AbandonableTask::doWork_wrapper()
{
Task::doWork_wrapper();
pthread_cond_signal(&done_cv);
done_cv.notify_one();
pthread_mutex_lock(&taskMutex);
bool abandoned = thAbandoned;
pthread_mutex_unlock(&taskMutex);
bool abandoned;
{
std::lock_guard<std::mutex> g(taskMutex);
abandoned = thAbandoned;
}
if (abandoned)
{
delete this;
@@ -18,12 +20,10 @@ void AbandonableTask::doWork_wrapper()
void AbandonableTask::Finish()
{
pthread_mutex_lock(&taskMutex);
while (!thDone)
{
pthread_cond_wait(&done_cv, &taskMutex);
std::unique_lock<std::mutex> l(taskMutex);
done_cv.wait(l, [this]() { return thDone; });
}
pthread_mutex_unlock(&taskMutex);
// Poll to make sure that the rest of the Task knows that it's
// done, not just us. This has to be done because the thread that started
@@ -37,23 +37,24 @@ void AbandonableTask::Finish()
void AbandonableTask::Abandon()
{
bool delete_this = false;
pthread_mutex_lock(&taskMutex);
if (thDone)
{
// If thDone is true, the thread has already finished. We're
// not calling Poll because it may call callbacks, which
// an abandoned task shouldn't do. Instead we just delete the
// AbandonableTask after unlocking the mutex.
delete_this = true;
std::lock_guard<std::mutex> g(taskMutex);
if (thDone)
{
// If thDone is true, the thread has already finished. We're
// not calling Poll because it may call callbacks, which
// an abandoned task shouldn't do. Instead we just delete the
// AbandonableTask after unlocking the mutex.
delete_this = true;
}
else
{
// If at this point thDone is still false, the thread is still
// running, meaning we can safely set thAbandoned and let
// AbandonableTask::doWork_wrapper delete the AbandonableTask later.
thAbandoned = true;
}
}
else
{
// If at this point thDone is still false, the thread is still
// running, meaning we can safely set thAbandoned and let
// AbandonableTask::doWork_wrapper delete the AbandonableTask later.
thAbandoned = true;
}
pthread_mutex_unlock(&taskMutex);
if (delete_this)
{
@@ -64,11 +65,9 @@ void AbandonableTask::Abandon()
AbandonableTask::AbandonableTask() :
thAbandoned(false)
{
pthread_cond_init(&done_cv, NULL);
}
AbandonableTask::~AbandonableTask()
{
pthread_cond_destroy(&done_cv);
}

View File

@@ -3,9 +3,11 @@
#include "Task.h"
#include <condition_variable>
class AbandonableTask : public Task
{
pthread_cond_t done_cv;
std::condition_variable done_cv;
public:
void Finish();

View File

@@ -12,10 +12,7 @@ void Task::AddTaskListener(TaskListener * listener)
void Task::Start()
{
before();
// This would use a lambda if we didn't use pthreads and if I dared omit
// the TH_ENTRY_POINT from the function type.
pthread_create(&doWorkThread, 0, &Task::doWork_helper, this);
pthread_detach(doWorkThread);
std::thread([this]() { doWork_wrapper(); }).detach();
}
int Task::GetProgress()
@@ -52,13 +49,14 @@ void Task::Poll()
bool newSuccess = false;
String newStatus;
String newError;
pthread_mutex_lock(&taskMutex);
newProgress = thProgress;
newDone = thDone;
newSuccess = thSuccess;
newStatus = thStatus;
newError = thError;
pthread_mutex_unlock(&taskMutex);
{
std::lock_guard<std::mutex> g(taskMutex);
newProgress = thProgress;
newDone = thDone;
newSuccess = thSuccess;
newStatus = thStatus;
newError = thError;
}
success = newSuccess;
@@ -93,12 +91,10 @@ Task::Task() :
thDone(false),
listener(NULL)
{
pthread_mutex_init(&taskMutex, NULL);
}
Task::~Task()
{
pthread_mutex_destroy(&taskMutex);
}
void Task::before()
@@ -124,37 +120,29 @@ void Task::after()
void Task::doWork_wrapper()
{
bool newSuccess = doWork();
pthread_mutex_lock(&taskMutex);
thSuccess = newSuccess;
thDone = true;
pthread_mutex_unlock(&taskMutex);
}
TH_ENTRY_POINT void *Task::doWork_helper(void *ref)
{
((Task *)ref)->doWork_wrapper();
return NULL;
{
std::lock_guard<std::mutex> g(taskMutex);
thSuccess = newSuccess;
thDone = true;
}
}
void Task::notifyProgress(int progress)
{
pthread_mutex_lock(&taskMutex);
std::lock_guard<std::mutex> g(taskMutex);
thProgress = progress;
pthread_mutex_unlock(&taskMutex);
}
void Task::notifyStatus(String status)
{
pthread_mutex_lock(&taskMutex);
std::lock_guard<std::mutex> g(taskMutex);
thStatus = status;
pthread_mutex_unlock(&taskMutex);
}
void Task::notifyError(String error)
{
pthread_mutex_lock(&taskMutex);
std::lock_guard<std::mutex> g(taskMutex);
thError = error;
pthread_mutex_unlock(&taskMutex);
}
void Task::notifyProgressMain()

View File

@@ -2,9 +2,10 @@
#define TASK_H_
#include "common/String.h"
#include "common/tpt-thread.h"
#include "TaskListener.h"
#include "Config.h"
#include <thread>
#include <mutex>
class TaskListener;
class Task {
@@ -19,6 +20,7 @@ public:
virtual void Poll();
Task();
virtual ~Task();
protected:
int progress;
bool done;
@@ -32,16 +34,13 @@ protected:
String thStatus;
String thError;
TaskListener * listener;
pthread_t doWorkThread;
pthread_mutex_t taskMutex;
TaskListener *listener;
std::mutex taskMutex;
virtual void before();
virtual void after();
virtual bool doWork();
virtual void doWork_wrapper();
TH_ENTRY_POINT static void * doWork_helper(void * ref);
virtual void notifyProgress(int progress);
virtual void notifyError(String error);