mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-10 16:32:36 +00:00
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:
parent
883680f12b
commit
6bb6549228
2 changed files with 65 additions and 24 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue