evolution 使用GAsyncResult实现异步执行的例子
? 下面相关代码主要功能是:
在网络连接时,evolution发出准备联接信号,前端通知后端evolution-data-server进行长时逻辑,待后端逻辑处理完成后,前端收尾函数被自动调用。
?
? 这段代码主要几个知识点:
1.使用GSimpleAsyncResult进行异步操作。
2.使用g_object_add_toggle_ref进行引用趋势判断。由于前端无法知道evolution-data-server何时处理完成,并且不知道对应object会被多少后端逻辑进行引用。所以需要使用g_object_add_toggle_ref函数,当最后一个引用使用完成后,自动触发相关的收尾操作。
?
前端:
shell/e-shell.c:
static void
shell_prepare_for_online (EShell *shell)
{
??????? /* Are preparations already in progress? */
??????? if (shell->priv->preparing_for_line_change != NULL)
??????????????? return;
??????? shell->priv->preparing_for_line_change = e_activity_new ();
??????? e_activity_set_text (
??????????????? shell->priv->preparing_for_line_change,
??????????????? _("Preparing to go online..."));
?
??????? // 对preparing_for_line_change引用加一
??????? // 并且在对象最后一次被引用(引用计数从n到1)或者最后一次引用后被其他函数引用(引用计数从1到n)时
??????? // 调用回调 shell_ready_for_online
??????? g_object_add_toggle_ref (
??????????????? G_OBJECT (shell->priv->preparing_for_line_change),
??????????????? (GToggleNotify) shell_ready_for_online, shell);
??????? g_object_add_weak_pointer (
??????????????? G_OBJECT (shell->priv->preparing_for_line_change),
??????????????? &shell->priv->preparing_for_line_change);
??????? // 通知后端进行长时逻辑操作
??????? g_signal_emit (
??????????????? shell, signals[PREPARE_FOR_ONLINE], 0,
??????????????? shell->priv->preparing_for_line_change);
??????? g_object_unref (shell->priv->preparing_for_line_change);
}
static void
shell_ready_for_online (EShell *shell,
??????????????????????? EActivity *activity,
??????????????????????? gboolean is_last_ref)
{
??????? // 引用从n到1 is_last_ref = true
??????? // 引用从1到n is_last_ref = false
??????? if (!is_last_ref)
??????????????? return;
?
??????? // 引用为1,说明后端操作结束,前端准备发出信号并进行收尾
??????? /* Increment the reference count so we can safely emit
???????? * a signal without triggering the toggle reference. */
??????? g_object_ref (activity);
??????? e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
??????? g_object_remove_toggle_ref (
??????????????? G_OBJECT (activity), (GToggleNotify)
??????????????? shell_ready_for_online, shell);
??????? /* Finalize the activity. */
??????? g_object_unref (activity);
??????? shell->priv->online = TRUE;
??????? g_object_notify (G_OBJECT (shell), "online");
}
?
后端:
mail/e-mail-backend.c:
??????? // 后端关联信号进行长时操作
??????? g_signal_connect (
??????????????? shell, "prepare-for-online",
??????????????? G_CALLBACK (mail_backend_prepare_for_online_cb),
??????????????? shell_backend);
static void
mail_backend_prepare_for_online_cb (EShell *shell,
??????????????????????????????????? EActivity *activity,
??????????????????????????????????? EMailBackend *backend)
{
...
??????????????? // 对于标志activity引用+1
??????????????? // 当 e_mail_store_go_online长时操作结束后,自动调用mail_backend_store_operation_done_cb进行引用-1
??????????????? /* FIXME Not passing a GCancellable. */
??????????????? e_mail_store_go_online (
??????????????????????? CAMEL_STORE (service), G_PRIORITY_DEFAULT,
??????????????????????? NULL, (GAsyncReadyCallback)
??????????????????????? mail_backend_store_operation_done_cb,
??????????????????????? g_object_ref (activity));
...
}
/* Callback for various asynchronous CamelStore operations where
?* the EActivity's reference count is used as a counting semaphore. */
static void
mail_backend_store_operation_done_cb (CamelStore *store,
????????????????????????????????????? GAsyncResult *result,
????????????????????????????????????? EActivity *activity)
{
??????? /* FIXME Not checking result for error.? To fix this, we need
???????? *?????? separate callbacks to call different finish functions
???????? *?????? and then submit an EAlert on error. */
??????? g_object_unref (activity);
}
libemail-engine/e-mail-store-utils.c:
void
e_mail_store_go_online (CamelStore *store,
??????????????????????? gint io_priority,
??????????????????????? GCancellable *cancellable,
??????????????????????? GAsyncReadyCallback callback,
??????????????????????? gpointer user_data)
{
??????? GSimpleAsyncResult *simple;
??????? g_return_if_fail (CAMEL_IS_STORE (store));
??????? // 新建异步操作对象,设定操作结束后自动调用callback函数
??????? simple = g_simple_async_result_new (
??????????????? G_OBJECT (store), callback,
??????????????? user_data, e_mail_store_go_online);
?
??????? // 使用新线程进行长时操作mail_store_go_online_thread
??????? // 当mail_store_go_online_thread结束后自动调用GAsyncReadyCallback callback
??????? g_simple_async_result_run_in_thread (
??????????????? simple, (GSimpleAsyncThreadFunc)
??????????????? mail_store_go_online_thread,
??????????????? io_priority, cancellable);
??????? g_object_unref (simple);
}
static void
mail_store_go_online_thread (GSimpleAsyncResult *simple,
???????????????????????????? CamelStore *store,
???????????????????????????? GCancellable *cancellable)
{
??????? // 下面是长时操作
??????? CamelService *service;
??????? const gchar *display_name;
??????? GError *error = NULL;
??????? service = CAMEL_SERVICE (store);
??????? display_name = camel_service_get_display_name (service);
??????? if (display_name == NULL || *display_name == '\0')
??????????????? display_name = G_OBJECT_TYPE_NAME (service);
??????? camel_operation_push_message (
??????????????? cancellable, _("Reconnecting to '%s'"), display_name);
??????? if (CAMEL_IS_DISCO_STORE (store))
??????????????? camel_disco_store_set_status (
??????????????????????? CAMEL_DISCO_STORE (store),
??????????????????????? CAMEL_DISCO_STORE_ONLINE,
??????????????????????? cancellable, &error);
??????? else if (CAMEL_IS_OFFLINE_STORE (store))
??????????????? camel_offline_store_set_online_sync (
??????????????????????? CAMEL_OFFLINE_STORE (store),
??????????????????????? TRUE, cancellable, &error);
??????? if (error != NULL)
??????????????? g_simple_async_result_take_error (simple, error);
??????? camel_operation_pop_message (cancellable);
}