OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
GpuExecutionOwner.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
11
12#pragma once
13#include <condition_variable>
14#include <deque>
15#include <functional>
16#include <future>
17#include <memory>
18#include <mutex>
19#include <thread>
20#include <type_traits>
21
22namespace openswmm::twoD {
23// All core-controlled Kokkos entry points share one controlling host thread.
24// Calls are synchronous to the engine: borrowed buffers remain valid until
25// completion, and two GUI workers cannot initialize/dispatch concurrently.
27public:
36 static std::shared_ptr<GpuExecutionOwner> shared() {
37 // Deliberately process-resident, like the Kokkos runtime/plugins.
38 // A static shared_ptr destructor would join during DLL teardown on
39 // Windows, where thread synchronization can deadlock on the loader
40 // lock. The factory pins the containing module before first use.
41 static const auto* owner =
42 new std::shared_ptr<GpuExecutionOwner>(std::make_shared<GpuExecutionOwner>());
43 return *owner;
44 }
45
51 GpuExecutionOwner() : worker_([this] { work(); }) {}
60 {
61 std::lock_guard lock(mutex_);
62 stopping_ = true;
63 }
64 ready_.notify_one();
65 worker_.join();
66 }
80 template <class F> auto invoke(F&& fn) -> std::invoke_result_t<F> {
81 if (std::this_thread::get_id() == worker_.get_id())
82 return fn();
83 using R = std::invoke_result_t<F>;
84 auto task = std::make_shared<std::packaged_task<R()>>(std::forward<F>(fn));
85 auto result = task->get_future();
86 {
87 std::lock_guard lock(mutex_);
88 queue_.emplace_back([task] { (*task)(); });
89 }
90 ready_.notify_one();
91 return result.get();
92 }
93
94private:
102 void work() {
103 for (;;) {
104 std::function<void()> task;
105 {
106 std::unique_lock lock(mutex_);
107 ready_.wait(lock, [this] { return stopping_ || !queue_.empty(); });
108 if (queue_.empty())
109 return;
110 task = std::move(queue_.front());
111 queue_.pop_front();
112 }
113 task();
114 }
115 }
116 std::mutex mutex_;
117 std::condition_variable ready_;
118 std::deque<std::function<void()>> queue_;
119 bool stopping_ = false;
120 std::thread worker_;
121};
122}
static std::shared_ptr< GpuExecutionOwner > shared()
Acquire the process-resident controlling thread for matched GPU plugins.
Definition GpuExecutionOwner.hpp:36
GpuExecutionOwner(const GpuExecutionOwner &)=delete
~GpuExecutionOwner()
Stop and join a nonresident execution owner after queued work drains.
Definition GpuExecutionOwner.hpp:59
GpuExecutionOwner()
Start a dedicated synchronous-dispatch worker.
Definition GpuExecutionOwner.hpp:51
auto invoke(F &&fn) -> std::invoke_result_t< F >
Execute one callable on the controlling thread and wait for completion.
Definition GpuExecutionOwner.hpp:80
Definition ExchangeLaw.hpp:60