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

猜你喜欢

转载自socol.iteye.com/blog/1561789