Created
July 8, 2026 03:03
-
-
Save lidaobing/fb2efd54552aafeadc4b5effc61364d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <gio/gio.h> | |
| #include <glib.h> | |
| #include <stdint.h> | |
| #include <stdatomic.h> | |
| // ============================================================================ | |
| // 1. 宏定义与核心工具 (Macros & Utilities) | |
| // ============================================================================ | |
| // 仿 RAII 自动加解锁宏 | |
| #define WITH_MUTEX_LOCK(mutex) \ | |
| for (gboolean _lock_done = (g_mutex_lock(&(mutex)), TRUE); \ | |
| _lock_done; \ | |
| g_mutex_unlock(&(mutex)), _lock_done = FALSE) | |
| // 线程所有权断言宏 | |
| #ifdef G_ENABLE_DEBUG | |
| #define ASSERT_IN_BUSINESS_THREAD() g_assert_true (g_main_context_is_owner (business_context)) | |
| #define ASSERT_IN_UI_THREAD() g_assert_true (g_main_context_is_owner (NULL)) | |
| #else | |
| #define ASSERT_IN_BUSINESS_THREAD() ((void)0) | |
| #define ASSERT_IN_UI_THREAD() ((void)0) | |
| #endif | |
| // 模拟国际化宏(如果实际项目中没有 gettext,通常这样 fallback) | |
| #ifndef _ | |
| #define _(String) (String) | |
| #endif | |
| // ============================================================================ | |
| // 2. 业务任务抽象层 (Business Task Abstraction) | |
| // ============================================================================ | |
| typedef struct _BusinessTask BusinessTask; | |
| typedef void (*BusinessTaskCallback) (BusinessTask *b_task, | |
| gpointer result_data, | |
| GError *error, | |
| gpointer user_data); | |
| typedef struct { | |
| gboolean (*start) (BusinessTask *b_task, GError **error); | |
| void (*finalize) (BusinessTask *b_task); | |
| } BusinessTaskOps; | |
| struct _BusinessTask { | |
| const BusinessTaskOps *ops; | |
| gpointer user_data; | |
| BusinessTaskCallback completion_callback; | |
| gpointer callback_user_data; | |
| }; | |
| // ============================================================================ | |
| // 3. 具体业务实现:下载任务 (Concrete Task: Download) | |
| // ============================================================================ | |
| typedef struct { | |
| gchar *url; | |
| } DownloadPrivate; | |
| static void | |
| on_download_async_ready (GObject *source, GAsyncResult *res, gpointer user_data) | |
| { | |
| BusinessTask *b_task = (BusinessTask *)user_data; | |
| DownloadPrivate *priv = (DownloadPrivate *)b_task->user_data; | |
| // 此时绝对在业务线程执行 | |
| ASSERT_IN_BUSINESS_THREAD(); | |
| gchar *downloaded_content = g_strdup ("<html>Content From Server</html>"); | |
| if (b_task->completion_callback) { | |
| b_task->completion_callback (b_task, downloaded_content, NULL, b_task->callback_user_data); | |
| } | |
| b_task->ops->finalize (b_task); | |
| g_free (b_task); | |
| } | |
| static gboolean | |
| download_task_start (BusinessTask *b_task, GError **error) | |
| { | |
| ASSERT_IN_BUSINESS_THREAD(); | |
| DownloadPrivate *priv = (DownloadPrivate *)b_task->user_data; | |
| if (!priv->url || strlen(priv->url) == 0) { | |
| // I18N 友好的错误定义 | |
| g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("URL can not be empty.")); | |
| return FALSE; | |
| } | |
| // 模拟挂载一个非阻塞的异步 I/O (2秒后触发) | |
| g_timeout_add (2000, (GSourceFunc)on_download_async_ready, b_task); | |
| return TRUE; | |
| } | |
| static void | |
| download_task_finalize (BusinessTask *b_task) | |
| { | |
| DownloadPrivate *priv = (DownloadPrivate *)b_task->user_data; | |
| g_free (priv->url); | |
| g_free (priv); | |
| } | |
| static const BusinessTaskOps download_ops = { | |
| .start = download_task_start, | |
| .finalize = download_task_finalize | |
| }; | |
| BusinessTask * | |
| download_task_new (const gchar *url) | |
| { | |
| BusinessTask *b_task = g_new0 (BusinessTask, 1); | |
| b_task->ops = &download_ops; | |
| DownloadPrivate *priv = g_new0 (DownloadPrivate, 1); | |
| priv->url = g_strdup (url); | |
| b_task->user_data = priv; | |
| return b_task; | |
| } | |
| // ============================================================================ | |
| // 4. 业务群调度层 (Scheduler Layer) | |
| // ============================================================================ | |
| static GMainContext *business_context = NULL; | |
| static GThread *business_thread = NULL; | |
| static GMutex init_mutex; | |
| static GCond init_cond; | |
| static gboolean is_initialized = FALSE; | |
| static void | |
| scheduler_on_task_completed (BusinessTask *b_task, gpointer result_data, GError *error, gpointer user_data) | |
| { | |
| ASSERT_IN_BUSINESS_THREAD(); | |
| GTask *g_task = G_TASK (user_data); | |
| if (error) { | |
| g_task_return_error (g_task, g_error_copy (error)); | |
| } else { | |
| // 使用 g_free 作为销毁通知,GTask 会自动在 UI 线程释放 result_data 内存 | |
| g_task_return_pointer (g_task, result_data, g_free); | |
| } | |
| g_object_unref (g_task); | |
| } | |
| static gboolean | |
| scheduler_process_task (gpointer user_data) | |
| { | |
| ASSERT_IN_BUSINESS_THREAD(); | |
| gpointer *pair = (gpointer *)user_data; | |
| BusinessTask *b_task = (BusinessTask *)pair[0]; | |
| GTask *g_task = (GTask *)pair[1]; | |
| g_free (pair); | |
| GError *error = NULL; | |
| b_task->completion_callback = scheduler_on_task_completed; | |
| b_task->callback_user_data = g_task; | |
| if (!b_task->ops->start (b_task, &error)) { | |
| g_task_return_error (g_task, error); | |
| g_object_unref (g_task); | |
| if (b_task->ops->finalize) b_task->ops->finalize (b_task); | |
| g_free (b_task); | |
| } | |
| return G_SOURCE_REMOVE; | |
| } | |
| static gpointer | |
| business_thread_func (gpointer data) | |
| { | |
| GMainContext *context = g_main_context_new (); | |
| g_main_context_push_thread_default (context); | |
| GMainLoop *loop = g_main_loop_new (context, FALSE); | |
| g_mutex_lock (&init_mutex); | |
| business_context = context; | |
| is_initialized = TRUE; | |
| g_cond_signal (&init_cond); | |
| g_mutex_unlock (&init_mutex); | |
| g_main_loop_run (loop); | |
| g_main_loop_unref (loop); | |
| g_main_context_pop_thread_default (context); | |
| g_main_context_unref (context); | |
| return NULL; | |
| } | |
| void | |
| business_thread_init (void) | |
| { | |
| g_mutex_init (&init_mutex); | |
| g_cond_init (&init_cond); | |
| g_mutex_lock (&init_mutex); | |
| business_thread = g_thread_new ("business-worker", business_thread_func, NULL); | |
| while (!is_initialized) { | |
| g_cond_wait (&init_cond, &init_mutex); | |
| } | |
| g_mutex_unlock (&init_mutex); | |
| } | |
| // ============================================================================ | |
| // 5. UI 监视层与管道门槛 (UI Monitor & Pipeline Launcher) | |
| // ============================================================================ | |
| static GList *active_tasks_list = NULL; | |
| static GMutex active_tasks_mutex; | |
| static atomic_uint_fast64_t global_task_id_counter = 0; | |
| typedef struct { | |
| guint64 task_id; | |
| gchar *description; | |
| gint64 start_time; | |
| } UITaskTracker; | |
| static void | |
| on_ui_task_tracker_destroy (gpointer data) | |
| { | |
| // 注意:GTask 销毁通知通常在 UI 线程执行 | |
| UITaskTracker *tracker = (UITaskTracker *)data; | |
| WITH_MUTEX_LOCK (active_tasks_mutex) { | |
| active_tasks_list = g_list_remove (active_tasks_list, tracker); | |
| } | |
| gint64 duration = (g_get_monotonic_time () - tracker->start_time) / 1000; | |
| // I18N 友好 且 视觉清爽的 %jd 现代化打印 | |
| g_print (_("[UI Log] 🔴 Task Finished | ID: %jd | Desc: %s | Latency: %jd ms\n"), | |
| (intmax_t)tracker->task_id, tracker->description, (intmax_t)duration); | |
| g_free (tracker->description); | |
| g_free (tracker); | |
| } | |
| void | |
| ui_task_pipeline_launch (BusinessTask *b_task, const gchar *description, GAsyncReadyCallback callback, gpointer user_data) | |
| { | |
| ASSERT_IN_UI_THREAD(); | |
| GTask *g_task = g_task_new (NULL, NULL, callback, user_data); | |
| UITaskTracker *tracker = g_new0 (UITaskTracker, 1); | |
| // C11 原子无锁自增 | |
| tracker->task_id = atomic_fetch_add (&global_task_id_counter, 1) + 1; | |
| tracker->description = g_strdup (description); | |
| tracker->start_time = g_get_monotonic_time (); | |
| g_task_set_task_data (g_task, tracker, on_ui_task_tracker_destroy); | |
| WITH_MUTEX_LOCK (active_tasks_mutex) { | |
| active_tasks_list = g_list_append (active_tasks_list, tracker); | |
| } | |
| g_print (_("[UI Log] 🟢 Task Launched | ID: %jd | Desc: %s\n"), | |
| (intmax_t)tracker->task_id, tracker->description); | |
| gpointer *pair = g_new (gpointer, 2); | |
| pair[0] = b_task; | |
| pair[1] = g_task; | |
| g_main_context_invoke (business_context, scheduler_process_task, pair); | |
| } | |
| // ============================================================================ | |
| // 6. 应用程序上层入口测试 (Main Entry & Test) | |
| // ============================================================================ | |
| static void | |
| on_my_download_completed (GObject *source, GAsyncResult *res, gpointer user_data) | |
| { | |
| ASSERT_IN_UI_THREAD(); | |
| GError *error = NULL; | |
| // 从 GTask 中取出被包裹的返回指针 | |
| gchar *content = (gchar *)g_task_propagate_pointer (G_TASK (res), &error); | |
| if (error) { | |
| g_printerr (_("[UI View] Error occurred: %s\n"), error->message); | |
| g_clear_error (&error); | |
| } else { | |
| g_print (_("[UI View] Successfully rendered UI with data: %s\n"), content); | |
| g_free (content); // 释放上层拿到的指针 | |
| } | |
| // 测试完毕,退出主循环 | |
| GMainLoop *ui_loop = (GMainLoop *)user_data; | |
| g_main_loop_quit (ui_loop); | |
| } | |
| int | |
| main (int argc, char *argv[]) | |
| { | |
| g_mutex_init (&active_tasks_mutex); | |
| // 1. 初始化后台业务线程 | |
| business_thread_init (); | |
| // 2. 创建主 UI 线程的 MainLoop | |
| GMainLoop *ui_loop = g_main_loop_new (NULL, FALSE); | |
| g_print ("[Main] App started. Simulating button click...\n"); | |
| // 3. 构建业务子类对象 | |
| BusinessTask *download_job = download_task_new ("https://api.example.com/data"); | |
| // 4. 通过管道发射任务 | |
| ui_task_pipeline_launch (download_job, "Download System Data", on_my_download_completed, ui_loop); | |
| // 5. 启动 UI 主循环 | |
| g_main_loop_run (ui_loop); | |
| // 6. 清理退出 | |
| g_main_loop_unref (ui_loop); | |
| g_mutex_clear (&active_tasks_mutex); | |
| g_mutex_clear (&init_mutex); | |
| g_cond_clear (&init_cond); | |
| g_print ("[Main] App exited cleanly.\n"); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment