mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
ListenerList: Prevent false positive assertions in callCheckedExcluding
This commit is contained in:
parent
6972c4f0e3
commit
76215d2dd0
2 changed files with 47 additions and 13 deletions
|
|
@ -229,25 +229,27 @@ public:
|
|||
const BailOutCheckerType& bailOutChecker,
|
||||
Callback&& callback)
|
||||
{
|
||||
#if JUCE_ASSERTIONS_ENABLED_OR_LOGGED
|
||||
// Keep a reference to the mutex to protect against the case where this list gets deleted
|
||||
// during a callback.
|
||||
auto localMutexPtr = callCheckedExcludingMutex;
|
||||
const ScopedTryLock callCheckedExcludingLock (*localMutexPtr);
|
||||
|
||||
// If you hit this assertion it means you're trying to call the listeners from multiple
|
||||
// threads concurrently. If you need to do this either use a LightweightListenerList, for a
|
||||
// lock free option, or a ThreadSafeListenerList if you also need the extra guarantees
|
||||
// provided by ListenerList. See the class descriptions for more details.
|
||||
jassert (callCheckedExcludingLock.isLocked());
|
||||
#endif
|
||||
|
||||
if (! initialised())
|
||||
return;
|
||||
|
||||
const auto localListeners = listeners;
|
||||
const ScopedLockType lock { localListeners->getLock() };
|
||||
|
||||
#if JUCE_ASSERTIONS_ENABLED_OR_LOGGED
|
||||
{
|
||||
// Keep a reference to the mutex to protect against the case where this list gets deleted
|
||||
// during a callback.
|
||||
auto localMutexPtr = callCheckedExcludingMutex;
|
||||
const ScopedTryLock callCheckedExcludingLock (*localMutexPtr);
|
||||
|
||||
// If you hit this assertion it means you're trying to call the listeners from multiple
|
||||
// threads concurrently. If you need to do this either use a LightweightListenerList, for a
|
||||
// lock free option, or a ThreadSafeListenerList if you also need the extra guarantees
|
||||
// provided by ListenerList. See the class descriptions for more details.
|
||||
jassert (callCheckedExcludingLock.isLocked());
|
||||
}
|
||||
#endif
|
||||
|
||||
Iterator it{};
|
||||
it.end = localListeners->size();
|
||||
|
||||
|
|
|
|||
|
|
@ -485,6 +485,38 @@ public:
|
|||
expect (numberOfCallbacks == 2);
|
||||
expect (listeners.size() == 2);
|
||||
}
|
||||
|
||||
beginTest ("ThreadSafeListenerList stress test");
|
||||
{
|
||||
struct Listener { void callback(){} };
|
||||
|
||||
ThreadPool threadPool { 10 };
|
||||
ThreadSafeListenerList<Listener> listeners;
|
||||
|
||||
for (int i = 0; i < 1'000; ++i)
|
||||
{
|
||||
threadPool.addJob ([&]
|
||||
{
|
||||
std::vector<std::unique_ptr<Listener>> listenersToAdd;
|
||||
|
||||
for (int j = 0; j < 1'000; ++j)
|
||||
{
|
||||
listenersToAdd.push_back (std::make_unique<Listener>());
|
||||
listeners.add (listenersToAdd.back().get());
|
||||
}
|
||||
|
||||
for (auto& listener : listenersToAdd)
|
||||
listeners.remove (listener.get());
|
||||
});
|
||||
|
||||
threadPool.addJob ([&]
|
||||
{
|
||||
listeners.call (&Listener::callback);
|
||||
});
|
||||
}
|
||||
|
||||
expect (threadPool.removeAllJobs (false, 30'000));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue