docs/design/part-MT-refcounting.txt (Refcounting): Some grammar/clarity fixes, and added a section on child structure...

Original commit message from CVS:
2005-02-10  Andy Wingo  <wingo@pobox.com>

* docs/design/part-MT-refcounting.txt (Refcounting): Some
grammar/clarity fixes, and added a section on child structures of
shared refcounted objects.
This commit is contained in:
Andy Wingo 2005-02-10 14:49:29 +00:00
parent 883680f12b
commit 6bb6549228
2 changed files with 65 additions and 24 deletions

View file

@ -1,3 +1,9 @@
2005-02-10 Andy Wingo <wingo@pobox.com>
* docs/design/part-MT-refcounting.txt (Refcounting): Some
grammar/clarity fixes, and added a section on child structures of
shared refcounted objects.
2005-02-10 Andy Wingo <wingo@pobox.com>
* docs/design/part-MT-refcounting.txt: Fill to 80 columns.

View file

@ -15,31 +15,34 @@ MT safety techniques
Several design patterns are used to guarantee object consistency in GStreamer.
This is an overview of the methods used in various GStreamer subsystems.
Refcounting
Refcounting:
All objects have a refcount associated with them. Each reference obtained to
the object should increase the refcount and each reference lost should
decrease the refcount.
All shared objects have a refcount associated with them. Each reference
obtained to the object should increase the refcount and each reference lost
should decrease the refcount.
The refcounting is used to make sure that when another thread destroys the
object, the ones which still hold a reference to the object do not read from
invalid memory when accessing the object.
It is a requirement that when two threads have a handle to an object, the
refcount must be one, this means that when one thread passes an object to
another thread it must increase the refcount. This requirement makes sure that
one thread cannot suddenly dispose the object making the other thread crash
when it tries to access the pointer to invalid memory.
Refcounting is also used to ensure that mutable data structures are only
modified when they are owned by the calling code.
Copy-on-write:
It is a requirement that when two threads have a handle on an object, the
refcount must be more than one. This means that when one thread passes an
object to another thread it must increase the refcount. This requirement makes
sure that one thread cannot suddenly dispose the object making the other
thread crash when it tries to access the pointer to invalid memory.
All object have a refcount associated with them. Each reference obtained to
Shared data structures and writability:
All objects have a refcount associated with them. Each reference obtained to
the object should increase the refcount and each reference lost should
decrease the refcount.
Each thread having a refcount to the object can safely read from the object.
but modifications made to the object should be preceeded with a
_copy_on_write() function call. This function will check the refcount of the
_get_writable() function call. This function will check the refcount of the
object and if the object is referenced by more than one instance, a copy is
made of the object that is then by definition only referenced from the calling
thread. This new copy is then modifyable without being visible to other
@ -51,15 +54,46 @@ Copy-on-write:
The advantage of this method is that no reader/writers locks are needed. all
threads can concurrently read but writes happen locally on a new copy. In most
cases _copy_on_write() can avoid a real copy because the calling method is the
cases _get_writable() can avoid a real copy because the calling method is the
only one holding a reference, wich makes read/writes very cheap.
The drawback is that sometimes 1 needless copy can be done. This would happen
when N threads call _copy_on_write() at the same time, all seeing that N
references are held to the object. In this case 1 copy too many will be done.
when N threads call _get_writable() at the same time, all seeing that N
references are held on the object. In this case 1 copy too many will be done.
This is not a problem in any practical situation because the copy operation is
fast.
Mutable substructures:
Special techniques are necessary to ensure the consistency of compound shared
objects. As mentioned above, shared objects need to have a reference count of
1 if they are to be modified. Implicit in this assumption is that all parts of
the shared object belong only to the object. For example, a GstStructure in
one GstCaps object should not belong to any other GstCaps object. This
condition suggests a parent-child relationship: structures can only be added
to parent object if they do not already have a parent object.
In addition, these substructures must not be modified while more than one code
segment has a reference on the parent object. For example, if the user creates
a GstStructure, adds it to a GstCaps, and the GstCaps is then referenced by
other code segments, the GstStructure should then become immutable, so that
changes to that data structure do not affect other parts of the code. This
means that the child is only mutable when the parent's reference count is 1,
as well as when the child structure has no parent.
The general solution to this problem is to include a field in child structures
pointing to the parent's atomic reference count. When set to NULL, this
indicates that the child has no parent. Otherwise, procedures that modify the
child structure must check if the parent's refcount is 1, and otherwise must
cause an error to be signaled.
Note that this is an internal implementation detail; application or plugin
code that calls _get_writable() on an object is guaranteed to receive an
object of refcount 1, which must then be writable. The only trick is that a
pointer to a child structure of an object is only valid while the calling code
has a reference on the parent object, because the parent is the owner of the
child.
Object locking:
For objects that contain state information and generally have a longer
@ -127,22 +161,23 @@ Objects
object if the FLOATING flag is set. The act of taking ownership of an object
is then performed as a _ref() followed by a _sink() call on the object.
Sinking objects is very usefull because you don't have to worry about the
lifetime of these sunken objects anymore since it is managed by the owner
element.
The float/sink process is very useful when initializing elements that will
then be placed under control of a parent. The floating ref keeps the object
alive until it is parented, and once the object is parented you can forget
about it.
* parent-child relations
One can create parent child relationships with the _object_set_parent()
method. This method sinks the object and assigns its parent property to that
of the managing parent.
One can create parent-child relationships with the _object_set_parent()
method. This method refs and sinks the object and assigns its parent property
to that of the managing parent.
The child is said to have a weak link to the parent since the refcount of the
parent is not increased in this process. This means that if the parent is
disposed it has to unset itself as the parent of the object before disposing
itself, else the child object holds a parent pointer to invalid memory.
The responsabilites for an object that sinks other objects are summarised as:
The responsibilites for an object that sinks other objects are summarised as:
- taking ownership of the object
- call _object_set_parent() to set itself as the object parent, this call
@ -223,11 +258,11 @@ Objects
* Accessor methods
For aplications it is encouraged to use the public methods of the object. Most
usefull operations can be performed with the methods so it is seldom required
useful operations can be performed with the methods so it is seldom required
to access the public fields manually.
All accessor methods that return an object should increase the refcount of the
returned object. The called should _unref() the object after usage. Each
returned object. The caller should _unref() the object after usage. Each
method should state this refcounting policy in the documentation.
* Accessing lists