.
......
Reference Counting
April 19, 2013
........ ..... ................. ................. ................. .... .... . .... ........ .
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
資源管理
• 在 concurrent 的環境很難確定 object 何時才沒有被使用
• 此時 reference counting 是一個不錯的管理方法
• object 紀錄目前 reference 的個數
• 當個數變為 0 時就做 deallocation
Reference Counting April 19, 2013 2 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
實作
struct Obj {
guint ref_count;
};
struct Obj * obj_ref(struct Obj *o) {
if (o) {
.. g_atomic_int_inc(&o->ref_count);
}
return o;
}
void obj_unref(struct Object *o) {
if (o && ..g_atomic_int_dec_and_test(&o->ref_count) ) {
obj_free(o);
}
}
..
遞增個數
.
遞減並檢查個數
Reference Counting April 19, 2013 3 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
使用規則
..1 複製 object pointer 前要先做 obj_ref,尤其是 asynchronous call 的
時候
..2 當 object 使用完要做 obj_unref
..3 如果 object pointer 沒有做過 obj_ref,要確保 obj_ref 完成前不會做
obj_unref
Reference Counting April 19, 2013 4 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
規則 1
gpointer thread(struct Obj *o) {
obj_unref(o);
return NULL;
}
void f(void) {
struct Obj *o = obj_new();
g_timeout_add_full(
G_PRIORITY_DEFAULT , 1000,
timeout , ..obj_ref(o) , (GDestroyNotify)obj_unref;
);
g_thread_new(NULL, (GThreadFunc)thread, ..obj_ref(o) );
obj_unref(o);
}
..
確保 object 在 timeout 時還存在
.
確保 object 在 thread 執行時還存在
Reference Counting April 19, 2013 5 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
規則 2
gpointer thread(struct Obj *o) {
.. obj_unref(o);
return NULL;
}
void f(void) {
struct Obj *o = obj_new();
g_timeout_add_full(
G_PRIORITY_DEFAULT , 1000,
timeout , obj_ref(o), (GDestroyNotify)..obj_unref ;
);
g_thread_new(NULL, (GThreadFunc)thread, obj_ref(o));
.. obj_unref(o);
}
..
lifetime 結束
.
lifetime 結束
.
lifetime 結束
Reference Counting April 19, 2013 6 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
規則 3
struct Obj * obj_table_get(gpointer key) {
struct Obj *o;
.. G_LOCK(lock);
.. o = g_hash_table_lookup(table, key);
o = obj_ref(o);
.. G_UNLOCK(lock);
return o;
}
void obj_table_put(struct Obj *o) {
.. G_LOCK(lock);
obj_unref(o);
.. G_UNLOCK(lock);
}
..
object 還沒做過 obj_ref
.
lock 起來確保順序是對的
.
lock 起來確保順序是對的
Reference Counting April 19, 2013 7 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
Global variable 的情況
static struct Obj *glob;
struct Obj * glob_get(void) {
struct Obj *o;
.. G_LOCK(lock);
o = obj_ref(glob);
.. G_UNLOCK(lock)
return o;
}
void glob_put(struct Obj *o) {
.. G_LOCK(lock);
obj_unref(o);
.. G_UNLOCK(lock)
}
void glob_set(struct Obj *o) {
.. G_LOCK(lock);
obj_unref(glob);
glob = obj_ref(o);
.. G_UNLOCK(lock)
}
..
一樣要 lock
.
一樣要 lock
.
一樣要 lock
Reference Counting April 19, 2013 8 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
Reference cycle
struct Obj * obj_new(void) {
struct Obj *o = g_malloc0(sizeof(*o));
o->ref_count = 1;
o->timeout = g_timeout_source_new(1000);
g_source_set_callback(
o->timeout , timeout ,
.. obj_ref(o) , (GDestroyNotify)obj_unref
);
g_source_attach(o->timeout , NULL);
g_source_unref(o->timeout);
return o;
}
void obj_table_add(gpointer key) {
G_LOCK(lock);
.. g_hash_table_insert(table, key, obj_new());
G_UNLOCK(lock);
}
..
reference cycle
Reference Counting April 19, 2013 9 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
解除 cycle
void obj_destroy(struct Obj *o) {
.. g_source_destroy(o->timeout);
obj_unref(o);
}
void obj_table_remove(gpointer key) {
G_LOCK(lock);
.. g_hash_table_remove(table, key);
G_UNLOCK(lock);
}
void obj_table_init(void) {
table = g_hash_table_new_full(
g_direct_hash , g_direct_equal ,
NULL, (GDestroyNotify)..obj_destroy
);
}
..
主動結束 child object 的 lifetime
.
value destructor
Reference Counting April 19, 2013 10 / 11
.....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
....
.
....
.
.....
.
....
.
.....
.
....
.
....
.
參考資料
• https://www.kernel.org/doc/Documentation/kref.txt
Reference Counting April 19, 2013 11 / 11

Reference Counting