事件源与线程的关系
事件源可以在任意线程中创建并可以 Attach 到任意的线程主上下文(GMainContext)上,Callback 由 Attach 的主线程上下文对应的线程调用。
异步方法与线程的关系
在 GIO 中,一个异步方法通常有两个类型的方法,分别是以 _async 和 _finish 结尾的。_async 方法用于发起一个异步调用,而 _finish 用于取得异步调用的结果。异步方法是使用线程实现的,大概的逻辑是一个线程在 _async 方法中创建新的线程,新线程执行一个事务,完成后通过一定的方法将结果通知给调用线程,调用线程再调用 _finish 方法取得异步方法的结果。
在 GLib 系统中,每个线程都有其主上下文(GMainContext),在一个线程中(主线程或其它线程)调用对象 _async 方法后,会创建一个 GSimpleAsyncResult 类型的对象,该对象用于保存和在调用线程与执行线程间传递数据。接着将方法调用需要的数据(即 _async 方法的参数)“打包“在一个结构体的实例中并设置到 GSimpleAsyncResult 的对象中保存。然后,会调用 g_simple_async_result_run_in_thread 方法并传入一个线程处理函数,该方法通过 GIOSchedulerJob 创建一个新的线程(通过一个专门的线程池),并执行传入的线程处理函数。当线程处理函数执行完成后,会将结果数据保存在 GSimpleAsyncResult 对象中(线程处理函数中实现)。接着会创建一个 GIldeSource 并 Attach 到调用 _async 方法的线程主上下文中,此事件源的 Callback 中会调用 _async 方法中传入的 GAsyncReadyCallback(由调用 _async 方法的线程调用)。最后,应该在 GAsyncReadyCallback 中调用对象的 _finish 方法取得异步调用的结果。
测试程序
/* async.c * Heiher <admin@heiher.info> * gcc -o async async.c `pkg-config --cflags --libs gio-2.0` */ #include <gio/gio.h> void enumerate_children_handler (GObject *obj, GAsyncResult *res, gpointer user_data) { GFileEnumerator *enumerator = NULL; enumerator = g_file_enumerate_children_finish (G_FILE (obj), res, NULL); g_file_enumerator_close_async (enumerator, G_PRIORITY_DEFAULT, NULL, NULL, NULL); g_object_unref (enumerator); g_debug ("Handler Thread: %p", g_thread_self ()); } gboolean source_handler (gpointer user_data) { g_debug ("Source Thread: %p", g_thread_self ()); return FALSE; } gpointer thread_handler (gpointer data) { GMainContext *context = data; GSource *source = NULL; g_debug ("Test Thread: %p", g_thread_self ()); source = g_idle_source_new (); g_source_set_priority (source, G_PRIORITY_DEFAULT); g_source_set_callback (source, source_handler, NULL, NULL); g_source_attach (source, context); g_source_unref (source); return FALSE; } int main (int argc, char *argv[]) { GMainLoop *main_loop = NULL; g_type_init (); main_loop = g_main_loop_new (NULL, FALSE); if (main_loop) { GFile *file = NULL; file = g_file_new_for_path ("/usr/lib"); g_debug ("Main Thread: %p", g_thread_self ()); g_file_enumerate_children_async (file, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, NULL, enumerate_children_handler, NULL); g_thread_new ("Test", thread_handler, g_main_context_default ()); g_main_loop_run (main_loop); g_object_unref (file); g_main_loop_unref (main_loop); } return 0; } |
运行结果
** (process:22820): DEBUG: Main Thread: 0x1aa4ca0 ** (process:22820): DEBUG: Test Thread: 0x1adac50 ** (process:22820): DEBUG: Source Thread: 0x1aa4ca0 ** (process:22820): DEBUG: Handler Thread: 0x1aa4ca0 |
Over!