Peer references
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Subject: Peer references
- Date: 27 Mar 2001 16:05:40 -0500
I've been tackling the issue of weak references in GTK+ recently,
and while thinking of this, came up with the following idea. (Not
really a GObject-2.0 idea, but wanted to write it down while I'm
thinking of it.)
Owen
There are several situations in which considering an object to be
either referenced or not referenced doesn't work well.
The two main ones are the following:
* A group of objects that should be kept alive if any of the
objects in the group is strongly referenced (peers). The
objects could all be GTK+ objects, but this more commonly
comes up when associating GTK+ objects with language bindings.
* A cache that wants to treat objects that are referenced only
by the cache differently than objects that are strongly
referenced. (E.g., a cache that wants to keep around at most
10 not-otherwise-referenced objects.)
An idea that had been floated for this is making the last
reference special in some way, but this is problematical because
there is no guarantee that there will only be one such reference.
So, my idea is to have multiple levels of references - and an
object is kept alive if it is referenced at any level. In the
simplest case there are two levels, strong references, and peer
references.
Then, there is notification when the strongest level of references
changes.
So, diagramatically, the way the first situation is handled looks
like.
+-+ -------> +-+
|A| |B| Initial state. A->B link peer reference, B->A link
+-+ <....... +-+ weak reference.
^
|
+-+ -------> +-+
|A| |B| B externally strongly referenced, A->B converted to
+-+ <------- +-+ peer reference.
^ ^
| |
+-+ .......> +-+
|A| |B| A only peer referenced, A->B converted to weak
+-+ <------- +-+ reference.
^
|
+-+ .......> +-+
|A| |B| B only peer referenced, B->A converted to weak
+-+ <....... +-+ reference.
Poof A and B finalized and freed.
The reason for having multiple levels is when you want to combine
the two above situations and have a group of peer objects refered
to from a cache, then you need to distinguish between:
- Peer group only referenced itself and in the cache
- Peer group only referenced by itself (and hence should be freed)
To be concrete about the interface, including multiple levels:
#define G_OBJECT_PEER_LEVEL_CACHE 10
#define G_OBJECT_PEER_LEVEL_PEER 20
typedef void (*GPeerWatchFunc) (GObject *object,
gint new_level,
gpointer data);
void g_object_peer_ref (GObject *object,
gint level);
void g_object_peer_unref (GObject *object,
gint level);
GPeerWatch *g_object_add_peer_watch (GObject *object,
GPeerWatchFunc peer_watch,
gpointer data);
void g_peer_watch_remove (GPeerWatch *watch);
Using this interface, the way you would implement a "peer link"
facility as diagrammed above would look like:
typedef struct
{
GObject *peer;
GPeerWatch *watch;
GWeakRef *self_weak_ref;
GWeakRef *peer_weak_ref;
} GPeerLink;
GPeerLink * g_peer_link_new (GObject *object,
GObject *peer);
void g_peer_link_remove (GPeerLink *watch);
static void
g_peer_link_remove (GPeerLink *link)
{
if (link->watch)
g_peer_watch_remove (link->watch);
if (link->self_weak_ref)
g_weak_ref_remove (link->self_weak_ref);
if (link->peer_weak_ref)
g_weak_ref_remove (link->peer_weak_ref);
g_free (link);
}
static void
peer_link_self_weak (GObject *object,
gpointer data)
{
GPeerLink *link = data;
link->watch = NULL;
link->self_weak_ref = NULL;
g_peer_link_remove (link);
}
static void
peer_link_other_weak (GObject *object,
gpointer data)
{
GPeerLink *link = data;
link->peer_weak_ref = NULL;
g_peer_link_remove (object, link);
}
static void
peer_link_watch (GObject *object,
gint new_level,
gpointer data)
{
GPeerLink *link = data;
if (level < G_OBJECT_PEER_LEVEL_PEER)
g_object_peer_ref (link->peer, G_OBJECT_PEER_LEVEL_PEER);
else
g_object_peer_unref (link->peer, G_OBJECT_PEER_LEVEL_PEER);
}
GPeerLink *
g_peer_link_new (GObject *object,
GObject *peer)
{
GPeerLink *link = g_new (GPeerLink, 1);
link->peer = peer;
link->self_weak_ref = g_object_weak_ref (object,
g_object_peer_self_weak_link,
link);
link->peer_weak_ref = g_object_weak_ref (peer,
g_object_peer_peer_weak_link,
link);
link->watch = g_object_add_peer_watch (object,
g_object_peer_link_watch,
link);
if (g_object_get_peer_level (object) < G_OBJECT_PEER_LEVEL_PEER)
g_object_peer_ref (link->peer);
return link;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]