There should be no problem constructing new instances of Tag,

Anchor and TagDirectives in separate threads anymore. D:YAML
still is not thread safe itself, though (it's the user's
responsibility to handle synchronization when working with a
single node from two threads, for example).
This commit is contained in:
Ferdinand Majerech 2011-10-14 19:54:41 +02:00
parent 765b74ffca
commit 23290239a7
2 changed files with 79 additions and 42 deletions

View file

@ -162,7 +162,7 @@ struct Node
Node.Pair[], Node[], YAMLObject) Value; Node.Pair[], Node[], YAMLObject) Value;
private: private:
//Stored value. ///Stored value.
Value value_; Value value_;
///Start position of the node. ///Start position of the node.
Mark startMark_; Mark startMark_;

View file

@ -7,6 +7,7 @@
///Shared object. ///Shared object.
module dyaml.sharedobject; module dyaml.sharedobject;
/** /**
* Mixin for shared objects (need a better name). * Mixin for shared objects (need a better name).
* *
@ -18,65 +19,92 @@ module dyaml.sharedobject;
* and when there are many instances of a data type that are mostly * and when there are many instances of a data type that are mostly
* duplicates (e.g. tags). * duplicates (e.g. tags).
* *
* Disadvantage is, this is not thread-safe (and neither is D:YAML, at the * This is not the most elegant way to store the extra data and might change in future.
* moment). That might be fixed in futurere, though.
*
* This is not the most elegant way to store the extra data and change in future.
*/ */
template SharedObject(T, MixedIn) template SharedObject(T, MixedIn)
{ {
private: private:
///Index of the object in objects_. ///This class stores the data that is shared between the objects.
class SharedData
{
private:
/**
* Reference count.
*
* When this reaches zero, objects_ are cleared. This is not
* the number of shared objects, but rather of objects using this kind
* of shared object. This is used e.g. with Anchor, but not with Tag
* - tags can be stored by the user in Nodes so there is no way to know
* when there are no Tags anymore.
*/
int referenceCount_ = 0;
///All known objects of type T are in this array.
T[] objects_;
public:
///Increment the reference count.
void addReference()
{
assert(referenceCount_ >= 0);
++referenceCount_;
}
///Decrement the reference count and clear the constructed objects if zero.
void removeReference()
{
--referenceCount_;
assert(referenceCount_ >= 0);
if(referenceCount_ == 0)
{
clear(objects_);
objects_ = [];
}
}
///Add an object and return its index.
uint add(ref T object)
{
foreach(uint index, ref T known; objects_)
{
if(object == known)
{
return index;
}
}
objects_ ~= object;
return cast(uint)objects_.length - 1;
}
///Get the object at specified object.
@property T get(in uint index)
{
return objects_[index];
}
}
///Index of the object in data_.
uint index_ = uint.max; uint index_ = uint.max;
/** ///Stores the actual objects.
* Reference count. static __gshared SharedData data_;
*
* When this reaches zero, objects_ are cleared. This count is not
* the number of shared objects, but rather of objects using this kind
* of shared object. This is used e.g. with Anchor, but not with Tag
* - tags can be stored by the user in Nodes so there is no way to know
* when there are no Tags anymore.
*/
static int referenceCount_ = 0;
/** static this()
* All known objects of this type are in this array.
*
* Note that this is not shared among threads.
* Working the same YAML file in multiple threads is NOT safe with D:YAML.
*/
static T[] objects_;
///Add a new object, checking if identical object already exists.
void add(ref T object)
{ {
foreach(uint index, known; objects_) data_ = new SharedData;
{
if(object == known)
{
index_ = index;
return;
}
}
index_ = cast(uint)objects_.length;
objects_ ~= object;
} }
public: public:
///Increment the reference count. ///Increment the reference count.
static void addReference() static void addReference()
{ {
assert(referenceCount_ >= 0); synchronized(data_){data_.addReference();}
++referenceCount_;
} }
///Decrement the reference count and clear the constructed objects if zero. ///Decrement the reference count and clear the constructed objects if zero.
static void removeReference() static void removeReference()
{ {
--referenceCount_; synchronized(data_){data_.removeReference();}
assert(referenceCount_ >= 0);
if(referenceCount_ == 0){objects_ = [];}
} }
///Get the object. ///Get the object.
@ -84,7 +112,9 @@ template SharedObject(T, MixedIn)
in{assert(!isNull());} in{assert(!isNull());}
body body
{ {
return objects_[index_]; T result;
synchronized(data_){result = data_.get(index_);}
return result;
} }
///Test for equality with another object. ///Test for equality with another object.
@ -95,5 +125,12 @@ template SharedObject(T, MixedIn)
///Is this object null (invalid)? ///Is this object null (invalid)?
bool isNull() const {return index_ == uint.max;} bool isNull() const {return index_ == uint.max;}
private:
///Add a new object, checking if identical object already exists.
void add(ref T object)
{
synchronized(data_){index_ = data_.add(object);}
}
} }