mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
MessageManager: Add callSync counterpart to callAsync
This commit is contained in:
parent
29cf6ecf04
commit
da09b99bbf
2 changed files with 61 additions and 39 deletions
|
|
@ -161,47 +161,9 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
|
|||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class AsyncFunctionCallback final : public MessageManager::MessageBase
|
||||
{
|
||||
public:
|
||||
AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param)
|
||||
: func (f), parameter (param)
|
||||
{}
|
||||
|
||||
void messageCallback() override
|
||||
{
|
||||
result = (*func) (parameter);
|
||||
finished.signal();
|
||||
}
|
||||
|
||||
WaitableEvent finished;
|
||||
std::atomic<void*> result { nullptr };
|
||||
|
||||
private:
|
||||
MessageCallbackFunction* const func;
|
||||
void* const parameter;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback)
|
||||
};
|
||||
|
||||
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
|
||||
{
|
||||
if (isThisTheMessageThread())
|
||||
return func (parameter);
|
||||
|
||||
// If this thread has the message manager locked, then this will deadlock!
|
||||
jassert (! currentThreadHasLockedMessageManager());
|
||||
|
||||
const ReferenceCountedObjectPtr<AsyncFunctionCallback> message (new AsyncFunctionCallback (func, parameter));
|
||||
|
||||
if (message->post())
|
||||
{
|
||||
message->finished.wait();
|
||||
return message->result.load();
|
||||
}
|
||||
|
||||
jassertfalse; // the OS message queue failed to send the message!
|
||||
return nullptr;
|
||||
return callSync ([func, parameter] { return func (parameter); }).value_or (nullptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ using MessageCallbackFunction = void* (void* userData);
|
|||
*/
|
||||
class JUCE_API MessageManager final
|
||||
{
|
||||
template <typename FunctionResult>
|
||||
using CallSyncResult = std::conditional_t<std::is_same_v<FunctionResult, void>,
|
||||
bool,
|
||||
std::optional<FunctionResult>>;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Returns the global instance of the MessageManager. */
|
||||
|
|
@ -142,6 +147,47 @@ public:
|
|||
*/
|
||||
void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData);
|
||||
|
||||
/** Similar to callFunctionOnMessageThread(), calls a function on the message thread,
|
||||
blocking the current thread until a result is available.
|
||||
|
||||
Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller
|
||||
thread has a critical section locked, which an unrelated message callback then tries to lock
|
||||
before the message thread gets round to processing this callback.
|
||||
|
||||
@param function the function to call, which should have no parameters
|
||||
@returns if function() returns void, then callSync returns a boolean where
|
||||
'true' indicates that the function was called successfully, and 'false'
|
||||
indicates that the message could not be posted.
|
||||
if function() returns any other type 'T', then callSync returns
|
||||
std::optional<T>, where the optional value will be valid if the function
|
||||
was called successfully, or nullopt otherwise.
|
||||
*/
|
||||
template <typename Function>
|
||||
static auto callSync (Function&& function) -> CallSyncResult<decltype (function())>
|
||||
{
|
||||
using FinalResult = CallSyncResult<decltype (function())>;
|
||||
|
||||
if (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
return transformResult (std::forward<Function> (function));
|
||||
|
||||
std::promise<FinalResult> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
const auto sent = callAsync ([p = std::move (promise), fn = std::move (function)]() mutable
|
||||
{
|
||||
p.set_value (transformResult (std::move (fn)));
|
||||
});
|
||||
|
||||
if (! sent)
|
||||
{
|
||||
// Failed to post message!
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
return future.get();
|
||||
}
|
||||
|
||||
/** Returns true if the caller-thread is the message thread. */
|
||||
bool isThisTheMessageThread() const noexcept;
|
||||
|
||||
|
|
@ -366,6 +412,20 @@ private:
|
|||
Atomic<Thread::ThreadID> threadWithLock;
|
||||
mutable std::mutex messageThreadIdMutex;
|
||||
|
||||
template <typename Function>
|
||||
static auto transformResult (Function&& f)
|
||||
{
|
||||
if constexpr (std::is_same_v<decltype (f()), void>)
|
||||
{
|
||||
f();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return f();
|
||||
}
|
||||
}
|
||||
|
||||
static bool postMessageToSystemQueue (MessageBase*);
|
||||
static void* exitModalLoopCallback (void*);
|
||||
static void doPlatformSpecificInitialisation();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue