gobject中比较常用,但是又比较生疏的数据类型quark/dataset。

os posted @ 2013年8月27日 15:13 in GObject , 1550 阅读

gobjec相关学习文章的list.

glib中除了提供

1. array/byte array/pointer array

2. SList/List

3. Hash Table

4. Queue

5. String

6. Tree

之外,还有quark/dataset, 这是gobject中用的非常多的。要理解它。

 

GQuark:

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, 那个这个指针数组是否很大?占用的内存如何?能否优化一些不用的?

 

GData

有了gquark后,就可以有GData了,这是和

gquark关联的一个数据元链表。

struct _GData
{
  GData *next;
  GQuark id;
  gpointer data;
  GDestroyNotify destroy_func;
};

这个data list, 并没有一个明显的全局变量来保持它。

1. 用时分配内存

2. 存放在一个全局的Hash Table中

3. 用完释放掉

 

GDataset:

 

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));

 

GObject中的qdata:

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

 Closure Array用quark来存取:

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);
}

 

Weak Reference用quark来存取:

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);
}

Toggle Reference用quark来存取:

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);

 

用的地方很多,非常多~

 

gobjec相关学习文章的list.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter