summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2023-04-14 13:13:47 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2023-04-14 13:13:47 +0100
commitf8ee56f6dc8cf7e92c4bfc5930d32b14f634141c (patch)
tree909ac21da2cd351a98022105bb7c76bc41259a76 /lib
parentSimplify doWork, add tests for various interface uses (diff)
downloadilt-f8ee56f6dc8cf7e92c4bfc5930d32b14f634141c.tar.bz2
ilt-f8ee56f6dc8cf7e92c4bfc5930d32b14f634141c.tar.xz
ilt-f8ee56f6dc8cf7e92c4bfc5930d32b14f634141c.zip
Current thread partakes in work effort while waiting
This will prevent deadlock if the work pool is otherwise busy by ensuring work is always being done
Diffstat (limited to 'lib')
-rw-r--r--lib/worker.cpp21
-rw-r--r--lib/worker.h26
2 files changed, 43 insertions, 4 deletions
diff --git a/lib/worker.cpp b/lib/worker.cpp
index 7e7f296..45fb6df 100644
--- a/lib/worker.cpp
+++ b/lib/worker.cpp
@@ -42,3 +42,24 @@ Worker::worker()
j->doWork();
}
}
+
+void
+Worker::assist()
+{
+ auto job = [this]() {
+ using namespace std::chrono_literals;
+ if (todoLen.try_acquire_for(100us)) {
+ if (std::lock_guard<std::mutex> lck {todoMutex}; todo.size()) {
+ WorkPtr x = std::move(todo.front());
+ if (x) {
+ todo.pop_front();
+ }
+ return x;
+ }
+ }
+ return WorkPtr {};
+ };
+ if (auto j = job()) {
+ j->doWork();
+ }
+}
diff --git a/lib/worker.h b/lib/worker.h
index 1bc7c14..d9a5a6f 100644
--- a/lib/worker.h
+++ b/lib/worker.h
@@ -14,12 +14,20 @@
class Worker {
public:
class WorkItem {
- public:
- WorkItem() = default;
+ protected:
+ WorkItem(Worker * worker) : worker {worker} { }
virtual ~WorkItem() = default;
NO_MOVE(WorkItem);
NO_COPY(WorkItem);
+ void
+ assist() const
+ {
+ worker->assist();
+ }
+ Worker * worker;
+
+ public:
virtual void doWork() = 0;
};
@@ -28,10 +36,16 @@ public:
T
get()
{
+ using namespace std::chrono_literals;
+ while (future.wait_for(0s) == std::future_status::timeout) {
+ assist();
+ }
return future.get();
}
protected:
+ WorkItemT(Worker * worker) : WorkItem {worker} { }
+
std::promise<T> promise;
std::future<T> future {promise.get_future()};
friend Worker;
@@ -48,7 +62,10 @@ public:
private:
template<typename T, typename... Params> class WorkItemTImpl : public WorkItemT<T> {
public:
- WorkItemTImpl(Params &&... params) : params {std::forward<Params>(params)...} { }
+ WorkItemTImpl(Worker * worker, Params &&... params) :
+ WorkItemT<T> {worker}, params {std::forward<Params>(params)...}
+ {
+ }
private:
void
@@ -84,13 +101,14 @@ private:
addWorkImpl(Params &&... params)
{
using T = decltype(std::invoke(std::forward<Params>(params)...));
- auto work = std::make_shared<WorkItemTImpl<T, Params...>>(std::forward<Params>(params)...);
+ auto work = std::make_shared<WorkItemTImpl<T, Params...>>(this, std::forward<Params>(params)...);
addWorkPtr(work);
return work;
}
void addWorkPtr(WorkPtr w);
void worker();
+ void assist();
using Threads = std::vector<std::jthread>;
using ToDo = std::deque<WorkPtr>;