[*] Added a few notes in the Async.hpp header

[+] Ensure dead locks can not occur
This commit is contained in:
Reece Wilson 2021-09-29 15:31:40 +01:00
parent d3a97257da
commit 2c5a492f08
2 changed files with 29 additions and 14 deletions

View File

@ -19,7 +19,16 @@ namespace Aurora::Async
using ThreadGroup_t = AuUInt8; using ThreadGroup_t = AuUInt8;
using ThreadId_t = AuUInt16; using ThreadId_t = AuUInt16;
/// ThreadGroup_t:
/// 0 = system main thread
/// 1+ = user defined
///
/// ThreadId_t:
/// 0 = invalid
/// index+1 = tid/runner id
///
using WorkerId_t = AuPair<ThreadGroup_t, ThreadId_t>; using WorkerId_t = AuPair<ThreadGroup_t, ThreadId_t>;
using DispatchTarget_t = AuPair<ThreadGroup_t, AuOptional<ThreadId_t>>; using DispatchTarget_t = AuPair<ThreadGroup_t, AuOptional<ThreadId_t>>;
struct WorkPriv struct WorkPriv
@ -65,25 +74,26 @@ namespace Aurora::Async
}; };
template<class Info_t = AVoid, class Result_t = AVoid> template<class Info_t = AVoid, class Result_t = AVoid>
static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Result_t &> &onSuccess) static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Info_t &, const Result_t &> &onSuccess)
{ {
FJob<Info_t, Result_t> ret; FJob<Info_t, Result_t> ret;
ret.onSuccess = [=](const Info_t &in, const Result_t &a) ret.onSuccess = [=](const Info_t &in, const Result_t &a)
{ {
onSuccess(a); onSuccess(in, a);
}; };
return ret; return ret;
} }
template<class Info_t = AVoid, class Result_t = AVoid> template<class Info_t = AVoid, class Result_t = AVoid>
static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Result_t &> &onSuccess, const AuConsumer<const Result_t &, bool/*neverDispatched*/> &onFailure) static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Info_t &, const Result_t &> &onSuccess, const AuConsumer<const Info_t &, bool/*neverDispatched*/> &onFailure)
{ {
FJob<Info_t, Result_t> ret; FJob<Info_t, Result_t> ret;
ret.onSuccess = [=](const Info_t &in, const Result_t &a) ret.onSuccess = [=](const Info_t &in, const Result_t &a)
{ {
onSuccess(a); onSuccess(in, a);
}; };
ret.onFailure = [=](const Result_t &a, bool neverDispatched) ret.onFailure = [=](const Info_t &a, bool neverDispatched)
{ {
onFailure(a, neverDispatched); onFailure(a, neverDispatched);
}; };
@ -91,14 +101,15 @@ namespace Aurora::Async
} }
template<class Info_t = AVoid, class Result_t = AVoid> template<class Info_t = AVoid, class Result_t = AVoid>
static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Result_t &> &onSuccess, const AuConsumer<const Result_t &> &onFailure) static inline FJob<Info_t, Result_t> JobFromConsumer(const AuConsumer<const Info_t &, const Result_t &> &onSuccess, const AuConsumer<const Info_t &> &onFailure)
{ {
FJob<Info_t, Result_t> ret; FJob<Info_t, Result_t> ret;
ret.onSuccess = [=](const Info_t &in, const Result_t &a) ret.onSuccess = [=](const Info_t &in, const Result_t &a)
{ {
onSuccess(a); onSuccess(in, a);
}; };
ret.onFailure = [=](const Result_t &a, bool neverDispatched) ret.onFailure = [=](const Info_t &a, bool neverDispatched)
{ {
onFailure(a); onFailure(a);
}; };
@ -107,7 +118,6 @@ namespace Aurora::Async
using FVoidJob = FJob<AVoid, AVoid>; using FVoidJob = FJob<AVoid, AVoid>;
template<class Info_t = AVoid, class Result_t = AVoid> template<class Info_t = AVoid, class Result_t = AVoid>
struct CJob struct CJob
{ {
@ -191,6 +201,7 @@ namespace Aurora::Async
AUKN_SYM AuSPtr<IWorkItem> NewWorkItem(const DispatchTarget_t &worker, const AuSPtr<IWorkItemHandler> &task, bool supportsBlocking = false); AUKN_SYM AuSPtr<IWorkItem> NewWorkItem(const DispatchTarget_t &worker, const AuSPtr<IWorkItemHandler> &task, bool supportsBlocking = false);
#pragma region EASE_OF_READING
struct BasicWorkStdFunc : IWorkItemHandler struct BasicWorkStdFunc : IWorkItemHandler
{ {
std::function<void()> callback; std::function<void()> callback;
@ -240,7 +251,6 @@ namespace Aurora::Async
}; };
#if !defined(_CPPSHARP) #if !defined(_CPPSHARP)
/// @hideinitializer /// @hideinitializer
struct BasicWorkCtx : WorkPriv struct BasicWorkCtx : WorkPriv
@ -517,6 +527,8 @@ namespace Aurora::Async
#endif #endif
#pragma endregion EASE_OF_READING
template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>> template<typename Info_t = AVoid, typename Result_t = AVoid, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
static AuSPtr<Async::IWorkItem> DispatchBasicWorkCallback(const DispatchTarget_t &worker, const Task_t &task, const Job_t &job, bool enableWait = false) static AuSPtr<Async::IWorkItem> DispatchBasicWorkCallback(const DispatchTarget_t &worker, const Task_t &task, const Job_t &job, bool enableWait = false)
{ {
@ -529,7 +541,6 @@ namespace Aurora::Async
return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t>>(task, job, inputParameters), enableWait)->Dispatch(); return Async::NewWorkItem(worker, AuMakeShared<Async::BasicWorkCallback<Info_t, Result_t>>(task, job, inputParameters), enableWait)->Dispatch();
} }
class IAsyncApp class IAsyncApp
{ {
public: public:
@ -547,6 +558,7 @@ namespace Aurora::Async
virtual WorkerId_t GetCurrentThread() = 0; virtual WorkerId_t GetCurrentThread() = 0;
// Synchronization // Synchronization
// Note: syncing to yourself will nullify requireSignal to prevent deadlock
virtual bool Sync(ThreadGroup_t group, bool requireSignal = false, AuUInt32 timeout = 0) = 0; virtual bool Sync(ThreadGroup_t group, bool requireSignal = false, AuUInt32 timeout = 0) = 0;
virtual void Signal(ThreadGroup_t group) = 0; virtual void Signal(ThreadGroup_t group) = 0;

View File

@ -585,11 +585,14 @@ namespace Aurora::Async
bool AsyncApp::Sync(ThreadGroup_t groupId, bool requireSignal, AuUInt32 timeoutMs) bool AsyncApp::Sync(ThreadGroup_t groupId, bool requireSignal, AuUInt32 timeoutMs)
{ {
AU_LOCK_GUARD(rwlock_->AsReadable()); AU_LOCK_GUARD(rwlock_->AsReadable());
auto group = GetGroup(groupId); auto group = GetGroup(groupId);
auto currentWorkerId = GetCurrentThread().second;
for (auto &jobWorker : group->workers) for (auto &jobWorker : group->workers)
{ {
if (!Barrier(jobWorker.second->id, timeoutMs, requireSignal, false)) // BAD!, should subtract time elapsed, clamp to, i dunno, 5ms min? if (!Barrier(jobWorker.second->id, timeoutMs, requireSignal && jobWorker.second->id.second != currentWorkerId, false)) // BAD!, should subtract time elapsed, clamp to, i dunno, 5ms min?
{ {
return false; return false;
} }