Threading: Remove a level of indirection from Promise and Mailbox.

Makes using small copyable or POD objects in these more efficient, and if you want
to you can just put a pointer or smart pointer in there, which will
effectively do the same thing as the old setup.
This commit is contained in:
Henrik Rydgård 2021-11-20 22:40:10 +01:00
parent 20c3c8f291
commit 4f85b8b2ef
5 changed files with 17 additions and 16 deletions

View File

@ -9,6 +9,7 @@
// well as a simple blocking mailbox. Let's see if we get there.
// Single item mailbox.
// T is copyable. Often T will itself just be a pointer or smart pointer of some sort.
template<class T>
struct Mailbox {
Mailbox() : refcount_(1) {}
@ -18,9 +19,9 @@ struct Mailbox {
std::mutex mutex_;
std::condition_variable condvar_;
T *data_ = nullptr;
T data_ = nullptr;
T *Wait() {
T Wait() {
std::unique_lock<std::mutex> lock(mutex_);
while (!data_) {
condvar_.wait(lock);
@ -28,7 +29,7 @@ struct Mailbox {
return data_;
}
bool Poll(T **data) {
bool Poll(T *data) {
std::unique_lock<std::mutex> lock(mutex_);
if (data_) {
*data = data_;
@ -38,7 +39,7 @@ struct Mailbox {
}
}
bool Send(T *data) {
bool Send(T data) {
std::unique_lock<std::mutex> lock(mutex_);
if (!data_) {
data_ = data;

View File

@ -9,7 +9,7 @@
template<class T>
class PromiseTask : public Task {
public:
PromiseTask(std::function<T *()> fun, Mailbox<T> *tx) : fun_(fun), tx_(tx) {
PromiseTask(std::function<T ()> fun, Mailbox<T> *tx) : fun_(fun), tx_(tx) {
tx_->AddRef();
}
~PromiseTask() {
@ -17,11 +17,11 @@ public:
}
void Run() override {
T *value = fun_();
T value = fun_();
tx_->Send(value);
}
std::function<T *()> fun_;
std::function<T ()> fun_;
Mailbox<T> *tx_;
};
@ -32,7 +32,7 @@ public:
template<class T>
class Promise {
public:
static Promise<T> *Spawn(ThreadManager *threadman, std::function<T *()> fun, TaskType taskType) {
static Promise<T> *Spawn(ThreadManager *threadman, std::function<T()> fun, TaskType taskType) {
Mailbox<T> *mailbox = new Mailbox<T>();
Promise<T> *promise = new Promise<T>();
@ -50,8 +50,8 @@ public:
delete data_;
}
// Returns *T if the data is ready, nullptr if it's not.
T *Poll() {
// Returns T if the data is ready, nullptr if it's not.
T Poll() {
if (ready_) {
return data_;
} else {
@ -66,7 +66,7 @@ public:
}
}
T *BlockUntilReady() {
T BlockUntilReady() {
if (ready_) {
return data_;
} else {
@ -81,7 +81,7 @@ public:
private:
Promise() {}
T *data_ = nullptr;
T data_ = nullptr;
bool ready_ = false;
Mailbox<T> *rx_;
};

View File

@ -645,7 +645,7 @@ UI::EventReturn ConfirmMemstickMoveScreen::OnConfirm(UI::EventParams &params) {
if (moveData_) {
progressReporter_.Set(iz->T("Starting move..."));
moveDataTask_ = Promise<MoveResult>::Spawn(&g_threadManager, [&]() -> MoveResult * {
moveDataTask_ = Promise<MoveResult *>::Spawn(&g_threadManager, [&]() -> MoveResult * {
Path moveSrc = g_Config.memStickDirectory;
Path moveDest = newMemstickFolder_;
if (moveSrc.GetFilename() != "PSP") {

View File

@ -130,7 +130,7 @@ private:
ProgressReporter progressReporter_;
UI::TextView *progressView_ = nullptr;
Promise<MoveResult> *moveDataTask_ = nullptr;
Promise<MoveResult *> *moveDataTask_ = nullptr;
std::string error_;
};

View File

@ -17,7 +17,7 @@ ResultObject *ResultProducer() {
}
bool TestMailbox() {
Mailbox<ResultObject> *mailbox = new Mailbox<ResultObject>();
Mailbox<ResultObject *> *mailbox = new Mailbox<ResultObject *>();
mailbox->Send(new ResultObject{ true });
ResultObject *data;
data = mailbox->Wait();
@ -60,7 +60,7 @@ bool TestThreadManager() {
ThreadManager manager;
manager.Init(8, 1);
Promise<ResultObject> *object(Promise<ResultObject>::Spawn(&manager, &ResultProducer, TaskType::IO_BLOCKING));
Promise<ResultObject *> *object(Promise<ResultObject *>::Spawn(&manager, &ResultProducer, TaskType::IO_BLOCKING));
if (!TestParallelLoop(&manager)) {
return false;