glib中除了提供
1. array/byte array/pointer array
2. SList/List
3. Hash Table
4. Queue
5. String
6. Tree
之外,还有quark/dataset, 这是gobject中用的非常多的。要理解它。
quark其实就是个数字,用来和字符串进行匹配。
只有一个gquark.h, 没有gquark.c
typedef guint32 GQuark;
实现文件在gdataset.c
static GHashTable *g_quark_ht = NULL; static gchar **g_quarks = NULL; static GQuark g_quark_seq_id = 0;
上面定义了一个hash table:g_quark_ht和一个全局的指针数组:g_quarks。
从下面的new中,我们可以很清楚的看到,string如何和数字对应的:
/* HOLDS: g_quark_global_lock */ static inline GQuark g_quark_new (gchar *string) { GQuark quark; if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0) g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE); if (!g_quark_ht) { g_assert (g_quark_seq_id == 0); g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal); g_quarks[g_quark_seq_id++] = NULL; } quark = g_quark_seq_id++; g_quarks[quark] = string; g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark)); return quark; }
会创建一个全局的Hash Table: g_quark_ht, 用来保持string/quark
同时把string放入数组中:g_quarks[quark] = string.
如果一个进程中有很多string, 那个这个指针数组是否很大?占用的内存如何?能否优化一些不用的?
有了gquark后,就可以有GData了,这是和
gquark关联的一个数据元链表。
struct _GData { GData *next; GQuark id; gpointer data; GDestroyNotify destroy_func; };
这个data list, 并没有一个明显的全局变量来保持它。
1. 用时分配内存
2. 存放在一个全局的Hash Table中
3. 用完释放掉
struct _GDataset { gconstpointer location; GData *datalist; };
Datalist的作用主要是:
给GObject关联任意数据。
Data lists are used for associating arbitrary data with #GObjects
定义了一个全局的Hash Table来保存,新生成的datalist
static GHashTable *g_dataset_location_ht = NULL; static GDataset *g_dataset_cached = NULL; /* should this be threadspecific? */
static void g_data_initialize (void) { g_return_if_fail (g_dataset_location_ht == NULL); g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL); g_dataset_cached = NULL; }
下面2个函数会把new的数据,放到hash table中:
void g_dataset_id_set_data_full (gconstpointer dataset_location, GQuark key_id, gpointer data, GDestroyNotify destroy_func)
void g_datalist_id_set_data_full (GData **datalist, GQuark key_id, gpointer data, GDestroyNotify destroy_func)
再仔细看下这个函数:
void g_dataset_id_set_data_full (gconstpointer dataset_location, GQuark key_id, gpointer data, GDestroyNotify destroy_func) { register GDataset *dataset; g_return_if_fail (dataset_location != NULL); if (!data) g_return_if_fail (destroy_func == NULL); if (!key_id) { if (data) g_return_if_fail (key_id > 0); else return; } G_LOCK (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); dataset = g_dataset_lookup (dataset_location); if (!dataset) { dataset = g_slice_new (GDataset); dataset->location = dataset_location; g_datalist_init (&dataset->datalist); g_hash_table_insert (g_dataset_location_ht, (gpointer) dataset->location, dataset); } g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset); G_UNLOCK (g_dataset_global); }
0. 先根据hash table的key查询一下,是否已经存在与之关联的dataset
如果没有,则新分配;如果有,则把相关的数据(data)放到这个data_list中
1. 上面是给GDataset分配一块内存
2. 把新的dataset插入到hash table中
3. 把用户想携带的data/destroy_func放到data_list中
在实际使用中g_dataset_xxx用的并不多,
而是g_datalist_xxx用的多:
#define g_datalist_id_set_data(dl, q, d) \ g_datalist_id_set_data_full ((dl), (q), (d), NULL)
实际使用中,GObject主要用了这个函数:g_datalist_id_set_data
void g_datalist_id_set_data_full (GData **datalist, GQuark key_id, gpointer data, GDestroyNotify destroy_func) { g_return_if_fail (datalist != NULL); if (!data) g_return_if_fail (destroy_func == NULL); if (!key_id) { if (data) g_return_if_fail (key_id > 0); else return; } G_LOCK (g_dataset_global); if (!g_dataset_location_ht) g_data_initialize (); g_data_set_internal (datalist, key_id, data, destroy_func, NULL); G_UNLOCK (g_dataset_global); }
查询一下:
Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark, data); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, g_quark_from_string (key), data); Gobjectnotifyqueue.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL); Gparam.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&pspec->qdata, quark, data); Gstobject.c (\gstreamer-0.10.36\gst): g_datalist_id_set_data (&object_name_counts, q, GINT_TO_POINTER (count + 1));
1. 内部使用的
2. 进一步封装,提供给调用者使用的APIs
在GObject自己内部用了3个quark来标识与之关联的data(任何数据)
static GQuark quark_closure_array = 0; static GQuark quark_weak_refs = 0; static GQuark quark_toggle_refs = 0;
再复杂的data, 用这个quark/datalist, 都可以绑定/提取,这样看来datalist还是很强大滴~
Gobject.c (\glib-2.28.6\gobject):static GQuark quark_closure_array = 0; Gobject.c (\glib-2.28.6\gobject): quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); Gobject.c (\glib-2.28.6\gobject): carray = g_object_get_qdata (object, quark_closure_array); Gobject.c (\glib-2.28.6\gobject): * letting it fiddle with quark_closure_array which is empty anyways Gobject.c (\glib-2.28.6\gobject): carray = g_datalist_id_remove_no_notify (&object->qdata, quark_closure_array); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array);
---- quark_weak_refs Matches (7 in 1 files) ---- Gobject.c (\glib-2.28.6\gobject):static GQuark quark_weak_refs = 0; Gobject.c (\glib-2.28.6\gobject): quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); Gobject.c (\glib-2.28.6\gobject): wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_refs); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data_full (&object->qdata, quark_weak_refs, wstack, weak_refs_notify); Gobject.c (\glib-2.28.6\gobject): wstack = g_datalist_id_get_data (&object->qdata, quark_weak_refs); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL);
---- quark_toggle_refs Matches (6 in 1 files) ---- Gobject.c (\glib-2.28.6\gobject):static GQuark quark_toggle_refs = 0; Gobject.c (\glib-2.28.6\gobject): quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references"); Gobject.c (\glib-2.28.6\gobject): tstackptr = g_datalist_id_get_data (&object->qdata, quark_toggle_refs); Gobject.c (\glib-2.28.6\gobject): tstack = g_datalist_id_remove_no_notify (&object->qdata, quark_toggle_refs); Gobject.c (\glib-2.28.6\gobject): g_datalist_id_set_data_full (&object->qdata, quark_toggle_refs, tstack, Gobject.c (\glib-2.28.6\gobject): tstack = g_datalist_id_get_data (&object->qdata, quark_toggle_refs);
static void g_object_do_class_init (GObjectClass *class) { /* read the comment about typedef struct CArray; on why not to change this quark */ quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references");
上面这3个quark来标识GObject的3种重要数据:
1)GObject的Closure Array
2) Weak Reference
3) Toggle reference
void g_object_watch_closure (GObject *object, GClosure *closure) { CArray *carray; guint i; g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (closure != NULL); g_return_if_fail (closure->is_invalid == FALSE); g_return_if_fail (closure->in_marshal == FALSE); g_return_if_fail (object->ref_count > 0); /* this doesn't work on finalizing objects */ g_closure_add_invalidate_notifier (closure, object, object_remove_closure); g_closure_add_marshal_guards (closure, object, (GClosureNotify) g_object_ref, object, (GClosureNotify) g_object_unref); G_LOCK (closure_array_mutex); carray = g_datalist_id_remove_no_notify (&object->qdata, quark_closure_array); if (!carray) { carray = g_renew (CArray, NULL, 1); carray->object = object; carray->n_closures = 1; i = 0; } else { i = carray->n_closures++; carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i); } carray->closures[i] = closure; g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array); G_UNLOCK (closure_array_mutex); }
g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array);
这是把Closure Array用quark标识后,并且放入data list中
在g_object_unref()中:
g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL);
在dispose时也搞:
static void g_object_real_dispose (GObject *object) { g_signal_handlers_destroy (object); g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); }
void g_object_weak_ref (GObject *object, GWeakNotify notify, gpointer data) { WeakRefStack *wstack; guint i; g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (notify != NULL); g_return_if_fail (object->ref_count >= 1); G_LOCK (weak_refs_mutex); wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_refs); if (wstack) { i = wstack->n_weak_refs++; wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->weak_refs[0]) * i); } else { wstack = g_renew (WeakRefStack, NULL, 1); wstack->object = object; wstack->n_weak_refs = 1; i = 0; } wstack->weak_refs[i].notify = notify; wstack->weak_refs[i].data = data; g_datalist_id_set_data_full (&object->qdata, quark_weak_refs, wstack, weak_refs_notify); G_UNLOCK (weak_refs_mutex); }
void g_object_add_toggle_ref (GObject *object, GToggleNotify notify, gpointer data) { ToggleRefStack *tstack; guint i; g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (notify != NULL); g_return_if_fail (object->ref_count >= 1); g_object_ref (object); G_LOCK (toggle_refs_mutex); tstack = g_datalist_id_remove_no_notify (&object->qdata, quark_toggle_refs); if (tstack) { i = tstack->n_toggle_refs++; /* allocate i = tstate->n_toggle_refs - 1 positions beyond the 1 declared * in tstate->toggle_refs */ tstack = g_realloc (tstack, sizeof (*tstack) + sizeof (tstack->toggle_refs[0]) * i); } else { tstack = g_renew (ToggleRefStack, NULL, 1); tstack->object = object; tstack->n_toggle_refs = 1; i = 0; } /* Set a flag for fast lookup after adding the first toggle reference */ if (tstack->n_toggle_refs == 1) g_datalist_set_flags (&object->qdata, OBJECT_HAS_TOGGLE_REF_FLAG); tstack->toggle_refs[i].notify = notify; tstack->toggle_refs[i].data = data; g_datalist_id_set_data_full (&object->qdata, quark_toggle_refs, tstack, (GDestroyNotify)g_free); G_UNLOCK (toggle_refs_mutex); }
Gobject除了自己内部用的3个quark外,
还封装了一组API给外部调用:调用者可以自己定义自己的quark, 并且可以给object绑定/提取自己关系的数据:
gpointer g_object_get_qdata (GObject *object, GQuark quark); void g_object_set_qdata (GObject *object, GQuark quark, gpointer data); void g_object_set_qdata_full (GObject *object, GQuark quark, gpointer data, GDestroyNotify destroy); gpointer g_object_steal_qdata (GObject *object, GQuark quark); gpointer g_object_get_data (GObject *object, const gchar *key); void g_object_set_data (GObject *object, const gchar *key, gpointer data); void g_object_set_data_full (GObject *object, const gchar *key, gpointer data, GDestroyNotify destroy); gpointer g_object_steal_data (GObject *object, const gchar *key);
这一组首先是定义一个quark,
然后用quark来标识data, 并且进行绑定/提取操作:
gpointer g_object_get_qdata (GObject *object,
GQuark quark);
void g_object_set_qdata (GObject *object,
GQuark quark,
gpointer data);
void g_object_set_qdata_full (GObject *object,
GQuark quark,
gpointer data,
GDestroyNotify destroy);
gpointer g_object_steal_qdata (GObject *object,
GQuark quark);
下面这一组,不仅仅是quark, 可以用字符串来标识。
gpointer g_object_get_data (GObject *object,
const gchar *key);
void g_object_set_data (GObject *object,
const gchar *key,
gpointer data);
void g_object_set_data_full (GObject *object,
const gchar *key,
gpointer data,
GDestroyNotify destroy);
gpointer g_object_steal_data (GObject *object,
const gchar *key);
用的地方很多,非常多~