mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +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
|
#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)
|
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
|
||||||
{
|
{
|
||||||
if (isThisTheMessageThread())
|
return callSync ([func, parameter] { return func (parameter); }).value_or (nullptr);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ using MessageCallbackFunction = void* (void* userData);
|
||||||
*/
|
*/
|
||||||
class JUCE_API MessageManager final
|
class JUCE_API MessageManager final
|
||||||
{
|
{
|
||||||
|
template <typename FunctionResult>
|
||||||
|
using CallSyncResult = std::conditional_t<std::is_same_v<FunctionResult, void>,
|
||||||
|
bool,
|
||||||
|
std::optional<FunctionResult>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
/** Returns the global instance of the MessageManager. */
|
/** Returns the global instance of the MessageManager. */
|
||||||
|
|
@ -142,6 +147,47 @@ public:
|
||||||
*/
|
*/
|
||||||
void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData);
|
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. */
|
/** Returns true if the caller-thread is the message thread. */
|
||||||
bool isThisTheMessageThread() const noexcept;
|
bool isThisTheMessageThread() const noexcept;
|
||||||
|
|
||||||
|
|
@ -366,6 +412,20 @@ private:
|
||||||
Atomic<Thread::ThreadID> threadWithLock;
|
Atomic<Thread::ThreadID> threadWithLock;
|
||||||
mutable std::mutex messageThreadIdMutex;
|
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 bool postMessageToSystemQueue (MessageBase*);
|
||||||
static void* exitModalLoopCallback (void*);
|
static void* exitModalLoopCallback (void*);
|
||||||
static void doPlatformSpecificInitialisation();
|
static void doPlatformSpecificInitialisation();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue