Browse Source

Fix for subtle race condition in Value.

tags/2021-05-28
jules 11 years ago
parent
commit
824faca68b
2 changed files with 12 additions and 72 deletions
  1. +9
    -67
      modules/juce_data_structures/values/juce_Value.cpp
  2. +3
    -5
      modules/juce_data_structures/values/juce_Value.h

+ 9
- 67
modules/juce_data_structures/values/juce_Value.cpp View File

@@ -22,75 +22,18 @@
============================================================================== ==============================================================================
*/ */
struct SharedValueSourceUpdater : private AsyncUpdater
{
public:
SharedValueSourceUpdater() {}
void update (Value::ValueSource* const source)
{
{
const ScopedLock sl (lock);
sourcesNeedingUpdate.addIfNotAlreadyThere (source);
}
triggerAsyncUpdate();
}
void valueDeleted (Value::ValueSource* const source)
{
const ScopedLock sl (lock);
sourcesNeedingUpdate.removeFirstMatchingValue (source);
}
private:
Array<Value::ValueSource*> sourcesNeedingUpdate;
CriticalSection lock;
void handleAsyncUpdate() override
{
SharedResourcePointer<SharedValueSourceUpdater> localRef;
int maxCallbacks = sourcesNeedingUpdate.size();
for (;;)
{
ReferenceCountedObjectPtr<Value::ValueSource> toUpdate;
{
const ScopedLock sl (lock);
toUpdate = sourcesNeedingUpdate.remove (0);
}
if (toUpdate == nullptr)
break;
toUpdate->sendChangeMessage (true);
if (--maxCallbacks <= 0)
{
triggerAsyncUpdate();
break;
}
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater)
};
struct Value::ValueSource::Pimpl
{
SharedResourcePointer<SharedValueSourceUpdater> updater;
};
Value::ValueSource::ValueSource() Value::ValueSource::ValueSource()
{ {
} }
Value::ValueSource::~ValueSource() Value::ValueSource::~ValueSource()
{ {
if (pimpl != nullptr)
pimpl->updater->valueDeleted (this);
cancelPendingUpdate();
}
void Value::ValueSource::handleAsyncUpdate()
{
sendChangeMessage (true);
} }
void Value::ValueSource::sendChangeMessage (const bool synchronous) void Value::ValueSource::sendChangeMessage (const bool synchronous)
@@ -103,16 +46,15 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous)
{ {
const ReferenceCountedObjectPtr<ValueSource> localRef (this); const ReferenceCountedObjectPtr<ValueSource> localRef (this);
cancelPendingUpdate();
for (int i = numListeners; --i >= 0;) for (int i = numListeners; --i >= 0;)
if (Value* const v = valuesWithListeners[i]) if (Value* const v = valuesWithListeners[i])
v->callListeners(); v->callListeners();
} }
else else
{ {
if (pimpl == nullptr)
pimpl = new Pimpl();
pimpl->updater->update (this);
triggerAsyncUpdate();
} }
} }
} }


+ 3
- 5
modules/juce_data_structures/values/juce_Value.h View File

@@ -167,7 +167,8 @@ public:
of a ValueSource object. If you're feeling adventurous, you can create your own custom of a ValueSource object. If you're feeling adventurous, you can create your own custom
ValueSource classes to allow Value objects to represent your own custom data items. ValueSource classes to allow Value objects to represent your own custom data items.
*/ */
class JUCE_API ValueSource : public SingleThreadedReferenceCountedObject
class JUCE_API ValueSource : public ReferenceCountedObject,
private AsyncUpdater
{ {
public: public:
ValueSource(); ValueSource();
@@ -195,10 +196,7 @@ public:
SortedSet<Value*> valuesWithListeners; SortedSet<Value*> valuesWithListeners;
private: private:
struct Pimpl;
friend struct Pimpl;
friend struct ContainerDeletePolicy<Pimpl>;
ScopedPointer<Pimpl> pimpl;
void handleAsyncUpdate() override;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource)
}; };


Loading…
Cancel
Save