mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-11 00:42: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>
|
2005-02-10 Andy Wingo <wingo@pobox.com>
|
||||||
|
|
||||||
* docs/design/part-MT-refcounting.txt: Fill to 80 columns.
|
* 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.
|
Several design patterns are used to guarantee object consistency in GStreamer.
|
||||||
This is an overview of the methods used in various GStreamer subsystems.
|
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
|
All shared objects have a refcount associated with them. Each reference
|
||||||
the object should increase the refcount and each reference lost should
|
obtained to the object should increase the refcount and each reference lost
|
||||||
decrease the refcount.
|
should decrease the refcount.
|
||||||
|
|
||||||
The refcounting is used to make sure that when another thread destroys the
|
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
|
object, the ones which still hold a reference to the object do not read from
|
||||||
invalid memory when accessing the object.
|
invalid memory when accessing the object.
|
||||||
|
|
||||||
It is a requirement that when two threads have a handle to an object, the
|
Refcounting is also used to ensure that mutable data structures are only
|
||||||
refcount must be one, this means that when one thread passes an object to
|
modified when they are owned by the calling code.
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
the object should increase the refcount and each reference lost should
|
||||||
decrease the refcount.
|
decrease the refcount.
|
||||||
|
|
||||||
Each thread having a refcount to the object can safely read from the object.
|
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
|
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
|
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
|
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
|
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
|
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
|
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.
|
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
|
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
|
when N threads call _get_writable() at the same time, all seeing that N
|
||||||
references are held to the object. In this case 1 copy too many will be done.
|
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
|
This is not a problem in any practical situation because the copy operation is
|
||||||
fast.
|
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:
|
Object locking:
|
||||||
|
|
||||||
For objects that contain state information and generally have a longer
|
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
|
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.
|
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
|
The float/sink process is very useful when initializing elements that will
|
||||||
lifetime of these sunken objects anymore since it is managed by the owner
|
then be placed under control of a parent. The floating ref keeps the object
|
||||||
element.
|
alive until it is parented, and once the object is parented you can forget
|
||||||
|
about it.
|
||||||
|
|
||||||
* parent-child relations
|
* parent-child relations
|
||||||
|
|
||||||
One can create parent child relationships with the _object_set_parent()
|
One can create parent-child relationships with the _object_set_parent()
|
||||||
method. This method sinks the object and assigns its parent property to that
|
method. This method refs and sinks the object and assigns its parent property
|
||||||
of the managing parent.
|
to that of the managing parent.
|
||||||
|
|
||||||
The child is said to have a weak link to the parent since the refcount of the
|
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
|
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
|
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.
|
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
|
- taking ownership of the object
|
||||||
- call _object_set_parent() to set itself as the object parent, this call
|
- call _object_set_parent() to set itself as the object parent, this call
|
||||||
|
@ -223,11 +258,11 @@ Objects
|
||||||
* Accessor methods
|
* Accessor methods
|
||||||
|
|
||||||
For aplications it is encouraged to use the public methods of the object. Most
|
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.
|
to access the public fields manually.
|
||||||
|
|
||||||
All accessor methods that return an object should increase the refcount of the
|
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.
|
method should state this refcounting policy in the documentation.
|
||||||
|
|
||||||
* Accessing lists
|
* Accessing lists
|
||||||
|
|
Loading…
Reference in a new issue