MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Dispatch.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifdef MAYAFLUX_PLATFORM_MACOS
4#include <dispatch/dispatch.h>
5#endif
6
7#ifdef MAYAFLUX_PLATFORM_WINDOWS
8#include <windows.h>
9#ifdef ERROR
10#undef ERROR
11#endif // ERROR
12
13#define MAYAFLUX_WM_DISPATCH (WM_USER + 0x0001)
14#endif // MAYAFLUX_PLATFORM_WINDOWS
15
17
18#ifdef MAYAFLUX_PLATFORM_MACOS
19/**
20 * @brief Execute a function on the main dispatch queue (macOS only)
21 * @tparam Func Callable type
22 * @tparam Args Argument types
23 * @param func Function to execute
24 * @param args Arguments to forward to the function
25 *
26 * Schedules work on the main queue asynchronously. Returns immediately.
27 * Use this for GLFW operations that must execute on the main thread.
28 */
29template <typename Func, typename... Args>
30void dispatch_main_async(Func&& func, Args&&... args)
31{
32 dispatch_async(dispatch_get_main_queue(), ^{
33 std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
34 });
35}
36
37/**
38 * @brief Execute a function on the main dispatch queue and wait (macOS only)
39 * @tparam Func Callable type that returns a result
40 * @tparam Args Argument types
41 * @param func Function to execute
42 * @param args Arguments to forward to the function
43 * @return The result returned by func
44 *
45 * Schedules work on the main queue synchronously. Blocks until complete.
46 * WARNING: Can deadlock if called from main thread or during Cocoa modal loops.
47 */
48template <typename Func, typename... Args>
49auto dispatch_main_sync(Func&& func, Args&&... args) -> decltype(auto)
50{
51 using ResultType = std::invoke_result_t<Func, Args...>;
52
53 if constexpr (std::is_void_v<ResultType>) {
54 dispatch_sync(dispatch_get_main_queue(), ^{
55 std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
56 });
57 } else {
58 __block ResultType result;
59 dispatch_sync(dispatch_get_main_queue(), ^{
60 result = std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
61 });
62 return result;
63 }
64}
65
66/**
67 * @brief Execute a function on the main queue with timeout (macOS only)
68 * @tparam Func Callable type
69 * @tparam Args Argument types
70 * @param timeout_ms Timeout in milliseconds
71 * @param func Function to execute
72 * @param args Arguments to forward to the function
73 * @return true if completed before timeout, false if timed out
74 *
75 * Schedules work asynchronously and waits with timeout.
76 * Returns false if the operation doesn't complete in time.
77 */
78template <typename Func, typename... Args>
79bool dispatch_main_async_with_timeout(std::chrono::milliseconds timeout_ms, Func&& func, Args&&... args)
80{
81 auto completed = std::make_shared<std::atomic<bool>>(false); // Shared pointer for capture
82
83 dispatch_async(dispatch_get_main_queue(), ^{
84 std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
85 completed->store(true, std::memory_order_release);
86 });
87
88 auto start = std::chrono::steady_clock::now();
89 while (!completed->load(std::memory_order_acquire)) {
90 if (std::chrono::steady_clock::now() - start > timeout_ms) {
91 return false;
92 }
93 std::this_thread::sleep_for(std::chrono::milliseconds(1));
94 }
95
96 return true;
97}
98
99#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
100
101inline DWORD g_MainThreadId = 0; /// < Main thread ID, must be set at startup
102
103/**
104 * @brief Execute a function on the main thread asynchronously (Windows only)
105 * @tparam Func Callable type
106 * @tparam Args Argument types
107 * @param func Function to execute
108 * @param args Arguments to forward to the function
109 *
110 * Posts a message to the main thread's message queue to execute the function.
111 * Use this for GLFW operations that must execute on the main thread.
112 */
113template <typename Func, typename... Args>
114void dispatch_main_async(Func&& func, Args&&... args)
115{
116 auto task = [f = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable {
117 std::invoke(std::move(f), std::move(args)...);
118 };
119
120 auto* task_ptr = new std::function<void()>(std::move(task));
121
122 PostThreadMessage(g_MainThreadId, MAYAFLUX_WM_DISPATCH, 0, (LPARAM)task_ptr);
123}
124
125template <typename Func, typename... Args>
126auto dispatch_main_sync(Func&& func, Args&&... args) -> decltype(auto)
127{
128 return std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
129}
130
131#else
132// On linux platforms, these just execute directly
133template <typename Func, typename... Args>
134void dispatch_main_async(Func&& func, Args&&... args)
135{
136 std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
137}
138
139template <typename Func, typename... Args>
140auto dispatch_main_sync(Func&& func, Args&&... args) -> decltype(auto)
141{
142 return std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
143}
144
145template <typename Func, typename... Args>
146bool dispatch_main_async_with_timeout(std::chrono::milliseconds /*timeout_ms*/, Func&& func, Args&&... args)
147{
148 std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
149 return true;
150}
151#endif
152
153} // namespace MayaFlux::Parallel
auto dispatch_main_sync(Func &&func, Args &&... args) -> decltype(auto)
Definition Dispatch.hpp:140
void dispatch_main_async(Func &&func, Args &&... args)
Definition Dispatch.hpp:134
bool dispatch_main_async_with_timeout(std::chrono::milliseconds, Func &&func, Args &&... args)
Definition Dispatch.hpp:146