{"id":1463,"date":"2024-11-06T14:06:42","date_gmt":"2024-11-06T06:06:42","guid":{"rendered":"https:\/\/www.fanyamin.com\/wordpress\/?p=1463"},"modified":"2024-11-08T09:39:05","modified_gmt":"2024-11-08T01:39:05","slug":"glib%e4%b8%ad%e7%9a%84%e9%99%b7%e9%98%b1","status":"publish","type":"post","link":"https:\/\/www.fanyamin.com\/wordpress\/?p=1463","title":{"rendered":"glib\u4e2d\u7684\u9677\u9631"},"content":{"rendered":"<blockquote>\n<p>GLib is a general-purpose, portable utility library, which provides many useful data types, macros, type conversions, string utilities, file utilities, a mainloop abstraction, and so on.<\/p>\n<\/blockquote>\n<p>\u5728 Linux \u7cfb\u7edf\u4e0a\u505a C\/C++ \u8bed\u8a00\u7684\u5f00\u53d1, glib \u662f\u5e38\u7528\u7684 library, \u5927\u91cf\u7684\u7684 library \u4e5f\u57fa\u4e8e\u5b83, \u4f8b\u5982 gstreamer, libsoup \u7b49\u5927\u540d\u9f0e\u9f0e\u7684\u5de5\u5177\u548c\u5e93.<\/p>\n<h2>What is GMainContext?<\/h2>\n<blockquote>\n<p>GMainContext is a generalized implementation of an event loop, useful for implementing polled file I\/O or event-based widget systems (such as GTK). It is at the core of almost every GLib application. To understand GMainContext requires understanding poll() and polled I\/O.<\/p>\n<\/blockquote>\n<p>GMainContext \u662f\u4e8b\u4ef6\u5faa\u73af\u7684\u901a\u7528\u5b9e\u73b0\uff0c\u53ef\u7528\u4e8e\u5b9e\u73b0\u8f6e\u8be2\u6587\u4ef6 I\/O \u6216\u57fa\u4e8e\u4e8b\u4ef6\u7684\u684c\u9762\u5c0f\u7ec4\u4ef6\u7cfb\u7edf\uff08\u4f8b\u5982 GTK\uff09\u3002\u5b83\u662f\u51e0\u4e4e\u6240\u6709 GLib \u5e94\u7528\u7a0b\u5e8f\u7684\u6838\u5fc3\u3002\u8981\u7406\u89e3 GMainContext\uff0c\u9700\u8981\u7406\u89e3 poll() \u548c\u8f6e\u8be2 I\/O\u3002<\/p>\n<blockquote>\n<p>A GMainContext has a set of sources which are \u2018attached\u2019 to it, each of which can be thought of as an expected event with an associated callback function which will be invoked when that event is received; or equivalently as a set of file descriptors (FDs) to check. An event could be a timeout or data being received on a socket, for example. <\/p>\n<\/blockquote>\n<p>GMainContext \u5177\u6709\u4e00\u7ec4\u201c\u9644\u52a0\u201d\u5230\u5b83\u7684\u6e90\uff0c\u6bcf\u4e2a\u6e90\u90fd\u53ef\u4ee5\u88ab\u89c6\u4e3a\u4e00\u4e2a\u9884\u671f\u4e8b\u4ef6\uff0c\u5e76\u5e26\u6709\u4e00\u4e2a\u5173\u8054\u7684\u56de\u8c03\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u5c06\u5728\u6536\u5230\u8be5\u4e8b\u4ef6\u65f6\u8c03\u7528\uff1b\u6216\u8005\u7b49\u540c\u4e8e\u4e00\u7ec4\u8981\u68c0\u67e5\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26 (FD)\u3002\u4f8b\u5982\uff0c\u4e8b\u4ef6\u53ef\u80fd\u662f\u8d85\u65f6\u6216\u5728\u5957\u63a5\u5b57\u4e0a\u63a5\u6536\u6570\u636e\u3002<\/p>\n<blockquote>\n<p>One iteration of the event loop will:<\/p>\n<ul>\n<li>Prepare sources, determining if any of them are ready to dispatch immediately.<\/li>\n<li>Poll the sources, blocking the current thread until an event is received for one of the sources.<\/li>\n<li>Check which of the sources received an event (several could have).<\/li>\n<li>Dispatch callbacks from those sources.<\/li>\n<\/ul>\n<\/blockquote>\n<p>\u4e8b\u4ef6\u5faa\u73af\u7684\u4e00\u6b21\u8fed\u4ee3\u5c06\uff1a<\/p>\n<ul>\n<li>\n<p>\u51c6\u5907\u6e90\uff0c\u786e\u5b9a\u5176\u4e2d\u662f\u5426\u6709\u4efb\u4f55\u6e90\u5df2\u51c6\u5907\u597d\u7acb\u5373\u5206\u6d3e\u3002<\/p>\n<\/li>\n<li>\n<p>\u8f6e\u8be2\u6e90\uff0c\u963b\u6b62\u5f53\u524d\u7ebf\u7a0b\uff0c\u76f4\u5230\u6536\u5230\u5176\u4e2d\u4e00\u4e2a\u6e90\u7684\u4e8b\u4ef6\u3002<\/p>\n<\/li>\n<li>\n<p>\u68c0\u67e5\u54ea\u4e9b\u6e90\u63a5\u6536\u5230\u4e86\u4e8b\u4ef6\uff08\u53ef\u80fd\u6709\u591a\u4e2a\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>\u4ece\u8fd9\u4e9b\u6e90\u5206\u6d3e\u56de\u8c03\u3002<\/p>\n<\/li>\n<\/ul>\n<blockquote>\n<p>At its core, GMainContext is just a poll() loop, with the preparation, check and dispatch stages of the loop corresponding to the normal preamble and postamble in a typical poll() loop implementation. Typically, some complexity is needed in non-trivial poll()-using applications to track the lists of FDs which are being polled. Additionally, GMainContext adds a lot of useful functionality which vanilla poll() doesn\u2019t support. Most importantly, it adds thread safety.<\/p>\n<p>GMainContext is completely thread safe, meaning that a GSource can be created in one thread and attached to a GMainContext running in another thread. A typical use for this might be to allow worker threads to control which sockets are being listened to by a GMainContext in a central I\/O thread. Each GMainContext is \u2018acquired\u2019 by a thread for each iteration it\u2019s put through. Other threads cannot iterate a GMainContext without acquiring it, which guarantees that a GSource and its FDs will only be polled by one thread at once (since each GSource is attached to at most one GMainContext). A GMainContext can be swapped between threads across iterations, but this is expensive.<\/p>\n<p>GMainContext is used instead of poll() mostly for convenience, as it transparently handles dynamically managing the array of FDs to pass to poll(), especially when operating over multiple threads. This is done by encapsulating file descriptors inside a GSource, which decide whether those FDs should be passed to the poll() call on each \u2018prepare\u2019 stage of the main context iteration.<\/p>\n<\/blockquote>\n<p>\u4ece\u672c\u8d28\u4e0a\u8bb2\uff0cGMainContext \u53ea\u662f\u4e00\u4e2a poll() \u5faa\u73af\uff0c\u5faa\u73af\u7684\u51c6\u5907\u3001\u68c0\u67e5\u548c\u8c03\u5ea6\u9636\u6bb5\u5bf9\u5e94\u4e8e\u5178\u578b poll() \u5faa\u73af\u5b9e\u73b0\u4e2d\u7684\u6b63\u5e38\u524d\u5bfc\u548c\u540e\u5bfc\u3002\u901a\u5e38\uff0c\u5728\u4f7f\u7528 poll() \u7684\u590d\u6742\u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u9700\u8981\u4e00\u4e9b\u590d\u6742\u6027\u6765\u8ddf\u8e2a\u6b63\u5728\u8f6e\u8be2\u7684 FD \u5217\u8868\u3002\u6b64\u5916\uff0cGMainContext \u8fd8\u6dfb\u52a0\u4e86\u8bb8\u591a\u6709\u7528\u7684\u529f\u80fd\uff0c\u800c\u666e\u901a\u7684 poll() \u4e0d\u652f\u6301\u8fd9\u4e9b\u529f\u80fd\u3002\u6700\u91cd\u8981\u7684\u662f\uff0c\u5b83\u589e\u52a0\u4e86\u7ebf\u7a0b\u5b89\u5168\u6027\u3002<\/p>\n<p>GMainContext \u662f\u5b8c\u5168\u7ebf\u7a0b\u5b89\u5168\u7684\uff0c\u8fd9\u610f\u5473\u7740\u53ef\u4ee5\u5728\u4e00\u4e2a\u7ebf\u7a0b\u4e2d\u521b\u5efa GSource \u5e76\u5c06\u5176\u9644\u52a0\u5230\u5728\u53e6\u4e00\u4e2a\u7ebf\u7a0b\u4e2d\u8fd0\u884c\u7684 GMainContext\u3002\u8fd9\u79cd\u505a\u6cd5\u7684\u5178\u578b\u7528\u9014\u53ef\u80fd\u662f\u5141\u8bb8\u5de5\u4f5c\u7ebf\u7a0b\u63a7\u5236\u4e2d\u592e I\/O \u7ebf\u7a0b\u4e2d\u7684 GMainContext \u6b63\u5728\u76d1\u542c\u54ea\u4e9b\u5957\u63a5\u5b57\u3002\u6bcf\u4e2a GMainContext \u90fd\u4f1a\u88ab\u7ebf\u7a0b\u201c\u83b7\u53d6\u201d\uff0c\u7528\u4e8e\u6bcf\u6b21\u8fed\u4ee3\u3002\u5176\u4ed6\u7ebf\u7a0b\u65e0\u6cd5\u5728\u672a\u83b7\u53d6 GMainContext \u7684\u60c5\u51b5\u4e0b\u5bf9\u5176\u8fdb\u884c\u8fed\u4ee3\uff0c\u8fd9\u4fdd\u8bc1\u4e86 GSource \u53ca\u5176 FD \u4e00\u6b21\u53ea\u80fd\u88ab\u4e00\u4e2a\u7ebf\u7a0b\u8f6e\u8be2\uff08\u56e0\u4e3a\u6bcf\u4e2a GSource \u6700\u591a\u9644\u52a0\u5230\u4e00\u4e2a GMainContext\uff09\u3002GMainContext \u53ef\u4ee5\u5728\u8fed\u4ee3\u4e4b\u95f4\u5728\u7ebf\u7a0b\u4e4b\u95f4\u4ea4\u6362\uff0c\u4f46\u8fd9\u6837\u505a\u6210\u672c\u5f88\u9ad8\u3002<\/p>\n<p>\u4f7f\u7528 GMainContext \u4ee3\u66ff poll() \u4e3b\u8981\u662f\u4e3a\u4e86\u65b9\u4fbf\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u900f\u660e\u5730\u52a8\u6001\u7ba1\u7406\u8981\u4f20\u9012\u7ed9 poll() \u7684 FD \u6570\u7ec4\uff0c\u5c24\u5176\u662f\u5728\u591a\u7ebf\u7a0b\u64cd\u4f5c\u65f6\u3002\u8fd9\u662f\u901a\u8fc7\u5c06\u6587\u4ef6\u63cf\u8ff0\u7b26\u5c01\u88c5\u5728 GSource \u4e2d\u6765\u5b9e\u73b0\u7684\uff0cGSource \u51b3\u5b9a\u662f\u5426\u5e94\u5728\u4e3b\u4e0a\u4e0b\u6587\u8fed\u4ee3\u7684\u6bcf\u4e2a\u201c\u51c6\u5907\u201d\u9636\u6bb5\u5c06\u8fd9\u4e9b FD \u4f20\u9012\u7ed9 poll() \u8c03\u7528\u3002<\/p>\n<h2>What is GMainLoop?<\/h2>\n<p>GMainLoop is essentially the following few lines of code, once reference counting and locking have been removed:<\/p>\n<pre><code class=\"language-c\">loop-&gt;is_running = TRUE;\nwhile (loop-&gt;is_running)\n  {\n    if (quit_condition)\n      loop-&gt;is_running = FALSE;\n\n    g_main_context_iteration (context, TRUE);\n  }<\/code><\/pre>\n<blockquote>\n<p>Setting quit_condition to TRUE will cause the loop to terminate once the current main context iteration ends.<\/p>\n<p>Hence, GMainLoop is a convenient, thread-safe way of running a GMainContext to process events until a desired exit condition is met, at which point g_main_loop_quit() should be called. Typically, in a UI program, this will be the user clicking \u2018exit\u2019. In a socket handling program, this might be the final socket closing.<\/p>\n<p>It is important not to confuse main contexts with main loops. Main contexts do the bulk of the work: preparing source lists, waiting for events, and dispatching callbacks. A main loop simply iterates a context.<\/p>\n<\/blockquote>\n<p>\u5c06 quit_condition \u8bbe\u7f6e\u4e3a TRUE \u5c06\u5bfc\u81f4\u5faa\u73af\u5728\u5f53\u524d main contxt \u8fed\u4ee3\u7ed3\u675f\u540e\u7ec8\u6b62\u3002<\/p>\n<p>\u56e0\u6b64\uff0cGMainLoop \u662f\u4e00\u79cd\u65b9\u4fbf\u3001\u7ebf\u7a0b\u5b89\u5168\u7684\u65b9\u5f0f\uff0c\u7528\u4e8e\u8fd0\u884c GMainContext \u6765\u5904\u7406\u4e8b\u4ef6\uff0c\u76f4\u5230\u6ee1\u8db3\u6240\u9700\u7684\u9000\u51fa\u6761\u4ef6\uff0c\u6b64\u65f6\u5e94\u8c03\u7528 g_main_loop_quit()\u3002\u901a\u5e38\uff0c\u5728 UI \u7a0b\u5e8f\u4e2d\uff0c\u8fd9\u5c06\u662f\u7528\u6237\u5355\u51fb\u201c\u9000\u51fa\u201d\u3002\u5728\u5957\u63a5\u5b57\u5904\u7406\u7a0b\u5e8f\u4e2d\uff0c\u8fd9\u53ef\u80fd\u662f\u6700\u540e\u7684\u5957\u63a5\u5b57\u5173\u95ed\u3002<\/p>\n<p>\u91cd\u8981\u7684\u662f\u4e0d\u8981\u5c06 main context \u4e0e main loop \u6df7\u6dc6\u3002main context \u5b8c\u6210\u5927\u90e8\u5206\u5de5\u4f5c\uff1a\u51c6\u5907\u6e90\u5217\u8868\u3001\u7b49\u5f85\u4e8b\u4ef6\u548c\u8c03\u5ea6\u56de\u8c03\u3002main loop \u53ea\u662f\u8fed\u4ee3 main context\u3002<\/p>\n<h2>Default Contexts \u9ed8\u8ba4\u4e0a\u4e0b\u6587<\/h2>\n<blockquote>\n<p>One of the important features of GMainContext is its support for \u2018default\u2019 contexts. There are two levels of default context: the thread-default, and the global-default. The global-default (accessed using g_main_context_default()) is run by GTK when g_application_run() is called. It\u2019s also used for timeouts (g_timeout_add()) and idle callbacks (g_idle_add()) \u2014 these won\u2019t be dispatched unless the default context is running!<\/p>\n<p>Thread-default contexts are generally used for I\/O operations which need to run and dispatch callbacks in a thread. By calling g_main_context_push_thread_default() before starting an I\/O operation, the thread-default context is set and the I\/O operation can add its sources to that context. The context can then be run in a new main loop in an I\/O thread, causing the callbacks to be dispatched on that thread\u2019s stack rather than on the stack of the thread running the global-default main context. This allows I\/O operations to be run entirely in a separate thread without explicitly passing a specific GMainContext pointer around everywhere.<\/p>\n<p>Conversely, by starting a long-running operation with a specific thread-default context set, the calling code can guarantee that the operation\u2019s callbacks will be emitted in that context, even if the operation itself runs in a worker thread. This is the principle behind GTask: when a new GTask is created, it stores a reference to the current thread-default context, and dispatches its completion callback in that context, even if the task itself is run using g_task_run_in_thread().<\/p>\n<\/blockquote>\n<p>GMainContext \u7684\u4e00\u4e2a\u91cd\u8981\u7279\u6027\u662f\u5b83\u652f\u6301\u201c\u9ed8\u8ba4\u201d\u4e0a\u4e0b\u6587\u3002\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u6709\u4e24\u4e2a\u7ea7\u522b\uff1a\u7ebf\u7a0b\u9ed8\u8ba4\u548c\u5168\u5c40\u9ed8\u8ba4\u3002\u5168\u5c40\u9ed8\u8ba4\uff08\u4f7f\u7528 g_main_context_default() \u8bbf\u95ee\uff09\u5728\u8c03\u7528 g_application_run() \u65f6\u7531 GTK \u8fd0\u884c\u3002\u5b83\u8fd8\u7528\u4e8e\u8d85\u65f6\uff08g_timeout_add()\uff09\u548c\u7a7a\u95f2\u56de\u8c03\uff08g_idle_add()\uff09\u2014\u2014\u9664\u975e\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u6b63\u5728\u8fd0\u884c\uff0c\u5426\u5219\u4e0d\u4f1a\u5206\u6d3e\u8fd9\u4e9b\u56de\u8c03\uff01<\/p>\n<p>\u7ebf\u7a0b\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u901a\u5e38\u7528\u4e8e\u9700\u8981\u5728\u7ebf\u7a0b\u4e2d\u8fd0\u884c\u548c\u5206\u6d3e\u56de\u8c03\u7684 I\/O \u64cd\u4f5c\u3002\u901a\u8fc7\u5728\u542f\u52a8 I\/O \u64cd\u4f5c\u4e4b\u524d\u8c03\u7528 g_main_context_push_thread_default()\uff0c\u5c06\u8bbe\u7f6e\u7ebf\u7a0b\u9ed8\u8ba4\u4e0a\u4e0b\u6587\uff0c\u5e76\u4e14 I\/O \u64cd\u4f5c\u53ef\u4ee5\u5c06\u5176\u6e90\u6dfb\u52a0\u5230\u8be5\u4e0a\u4e0b\u6587\u3002\u7136\u540e\u53ef\u4ee5\u5728 I\/O \u7ebf\u7a0b\u4e2d\u7684\u65b0\u4e3b\u5faa\u73af\u4e2d\u8fd0\u884c\u4e0a\u4e0b\u6587\uff0c\u4ece\u800c\u5bfc\u81f4\u56de\u8c03\u5728\u8be5\u7ebf\u7a0b\u7684\u5806\u6808\u4e0a\u5206\u6d3e\uff0c\u800c\u4e0d\u662f\u5728\u8fd0\u884c\u5168\u5c40\u9ed8\u8ba4\u4e3b\u4e0a\u4e0b\u6587\u7684\u7ebf\u7a0b\u7684\u5806\u6808\u4e0a\u5206\u6d3e\u3002\u8fd9\u6837\u5c31\u53ef\u4ee5\u5728\u5355\u72ec\u7684\u7ebf\u7a0b\u4e2d\u5b8c\u5168\u8fd0\u884c I\/O \u64cd\u4f5c\uff0c\u800c\u65e0\u9700\u5230\u5904\u660e\u786e\u4f20\u9012\u7279\u5b9a\u7684 GMainContext \u6307\u9488\u3002<\/p>\n<p>\u76f8\u53cd\uff0c\u901a\u8fc7\u542f\u52a8\u5177\u6709\u7279\u5b9a\u7ebf\u7a0b\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u96c6\u7684\u957f\u65f6\u95f4\u8fd0\u884c\u7684\u64cd\u4f5c\uff0c\u8c03\u7528\u4ee3\u7801\u53ef\u4ee5\u4fdd\u8bc1\u64cd\u4f5c\u7684\u56de\u8c03\u5c06\u5728\u8be5\u4e0a\u4e0b\u6587\u4e2d\u53d1\u51fa\uff0c\u5373\u4f7f\u64cd\u4f5c\u672c\u8eab\u5728\u5de5\u4f5c\u7ebf\u7a0b\u4e2d\u8fd0\u884c\u3002\u8fd9\u662f GTask \u80cc\u540e\u7684\u539f\u7406\uff1a\u521b\u5efa\u65b0\u7684 GTask \u65f6\uff0c\u5b83\u4f1a\u5b58\u50a8\u5bf9\u5f53\u524d\u7ebf\u7a0b\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u7684\u5f15\u7528\uff0c\u5e76\u5728\u8be5\u4e0a\u4e0b\u6587\u4e2d\u8c03\u5ea6\u5176\u5b8c\u6210\u56de\u8c03\uff0c\u5373\u4f7f\u4efb\u52a1\u672c\u8eab\u662f\u4f7f\u7528 g_task_run_in_thread() \u8fd0\u884c\u7684\u3002<\/p>\n<blockquote>\n<p>For example, the code below will run a GTask which performs two writes in parallel from a thread. The callbacks for the writes will be dispatched in the worker thread, whereas the callback from the task as a whole will be dispatched in the interesting_context.<\/p>\n<\/blockquote>\n<p>\u4f8b\u5982\uff0c\u4e0b\u9762\u7684\u4ee3\u7801\u5c06\u8fd0\u884c\u4e00\u4e2a GTask\uff0c\u8be5 GTask \u4ece\u4e00\u4e2a\u7ebf\u7a0b\u5e76\u884c\u6267\u884c\u4e24\u4e2a\u5199\u5165\u64cd\u4f5c\u3002\u5199\u5165\u7684\u56de\u8c03\u5c06\u5728\u5de5\u4f5c\u7ebf\u7a0b\u4e2d\u8c03\u5ea6\uff0c\u800c\u6574\u4e2a\u4efb\u52a1\u7684\u56de\u8c03\u5c06\u5728 interesting_context \u4e2d\u8c03\u5ea6\u3002<\/p>\n<pre><code class=\"language-c\">typedef struct {\n  GMainLoop *main_loop;\n  guint n_remaining;\n} WriteData;\n\n\/* This is always called in the same thread as thread_cb() because\n * it\u2019s always dispatched in the @worker_context. *\/\nstatic void\nwrite_cb (GObject      *source_object,\n          GAsyncResult *result,\n          gpointer      user_data)\n{\n  WriteData *data = user_data;\n  GOutputStream *stream = G_OUTPUT_STREAM (source_object);\n  GError *error = NULL;\n  gssize len;\n\n  \/* Finish the write. *\/\n  len = g_output_stream_write_finish (stream, result, &amp;error);\n  if (error != NULL)\n    {\n      g_error (&quot;Error: %s&quot;, error-&gt;message);\n      g_error_free (error);\n    }\n\n  \/* Check whether all parallel operations have finished. *\/\n  write_data-&gt;n_remaining--;\n\n  if (write_data-&gt;n_remaining == 0)\n    {\n      g_main_loop_quit (write_data-&gt;main_loop);\n    }\n}\n\n\/* This is called in a new thread. *\/\nstatic void\nthread_cb (GTask        *task,\n           gpointer      source_object,\n           gpointer      task_data,\n           GCancellable *cancellable)\n{\n  \/* These streams come from somewhere else in the program: *\/\n  GOutputStream *output_stream1, *output_stream;\n  GMainContext *worker_context;\n  GBytes *data;\n  const guint8 *buf;\n  gsize len;\n\n  \/* Set up a worker context for the writes\u2019 callbacks. *\/\n  worker_context = g_main_context_new ();\n  g_main_context_push_thread_default (worker_context);\n\n  \/* Set up the writes. *\/\n  write_data.n_remaining = 2;\n  write_data.main_loop = g_main_loop_new (worker_context, FALSE);\n\n  data = g_task_get_task_data (task);\n  buf = g_bytes_get_data (data, &amp;len);\n\n  g_output_stream_write_async (output_stream1, buf, len,\n                               G_PRIORITY_DEFAULT, NULL, write_cb,\n                               &amp;write_data);\n  g_output_stream_write_async (output_stream2, buf, len,\n                               G_PRIORITY_DEFAULT, NULL, write_cb,\n                               &amp;write_data);\n\n  \/* Run the main loop until both writes have finished. *\/\n  g_main_loop_run (write_data.main_loop);\n  g_task_return_boolean (task, TRUE);  \/* ignore errors *\/\n\n  g_main_loop_unref (write_data.main_loop);\n\n  g_main_context_pop_thread_default (worker_context);\n  g_main_context_unref (worker_context);\n}\n\n\/* This can be called from any thread. Its @callback will always be\n * dispatched in the thread which currently owns\n * @interesting_context. *\/\nvoid\nparallel_writes_async (GBytes              *data,\n                       GMainContext        *interesting_context,\n                       GCancellable        *cancellable,\n                       GAsyncReadyCallback  callback,\n                       gpointer             user_data)\n{\n  GTask *task;\n\n  g_main_context_push_thread_default (interesting_context);\n\n  task = g_task_new (NULL, cancellable, callback, user_data);\n  g_task_set_task_data (task, data,\n                        (GDestroyNotify) g_bytes_unref);\n  g_task_run_in_thread (task, thread_cb);\n  g_object_unref (task);\n\n  g_main_context_pop_thread_default (interesting_context);\n}<\/code><\/pre>\n<h2>Implicit Use of the Global-Default Main Context<\/h2>\n<blockquote>\n<p>Several functions implicitly add sources to the global-default main context. They should not be used in threaded code. Instead, use g_source_attach() with the GSource created by the replacement function from the table below.<\/p>\n<p>Implicit use of the global-default main context means the callback functions are invoked in the main thread, typically resulting in work being brought back from a worker thread into the main thread.<\/p>\n<\/blockquote>\n<p>\u591a\u4e2a\u51fd\u6570\u4f1a\u9690\u5f0f\u5c06\u6e90\u6dfb\u52a0\u5230\u5168\u5c40\u9ed8\u8ba4\u4e3b\u4e0a\u4e0b\u6587\u4e2d\u3002\u5b83\u4eec\u4e0d\u5e94\u5728\u7ebf\u7a0b\u4ee3\u7801\u4e2d\u4f7f\u7528\u3002\u76f8\u53cd\uff0c\u5e94\u5c06 g_source_attach() \u4e0e\u4e0b\u8868\u4e2d\u66ff\u6362\u51fd\u6570\u521b\u5efa\u7684 GSource \u7ed3\u5408\u4f7f\u7528\u3002<\/p>\n<p>\u9690\u5f0f\u4f7f\u7528\u5168\u5c40\u9ed8\u8ba4\u4e3b\u4e0a\u4e0b\u6587\u610f\u5473\u7740\u56de\u8c03\u51fd\u6570\u5728\u4e3b\u7ebf\u7a0b\u4e2d\u8c03\u7528\uff0c\u901a\u5e38\u4f1a\u5bfc\u81f4\u5de5\u4f5c\u4ece\u5de5\u4f5c\u7ebf\u7a0b\u5e26\u56de\u5230\u4e3b\u7ebf\u7a0b\u3002<\/p>\n<table>\n<thead>\n<tr>\n<th>Do not use<\/th>\n<th>Use instead<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>g_timeout_add()<\/td>\n<td>g_timeout_source_new()<\/td>\n<\/tr>\n<tr>\n<td>g_idle_add()<\/td>\n<td>g_idle_source_new()<\/td>\n<\/tr>\n<tr>\n<td>g_child_watch_add()<\/td>\n<td>g_child_watch_source_new()<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>So to delay some computation in a worker thread, use the following code:<\/p>\n<pre><code class=\"language-c\">static guint\nschedule_computation (guint delay_seconds)\n{\n  \/* Get the calling context. *\/\n  GMainContext *context = g_main_context_get_thread_default ();\n\n  GSource *source = g_timeout_source_new_seconds (delay_seconds);\n  g_source_set_callback (source, do_computation, NULL, NULL);\n\n  guint id = g_source_attach (source, context);\n\n  g_source_unref (source);\n\n  \/* The ID can be used with the same @context to\n   * cancel the scheduled computation if needed. *\/\n  return id;\n}\n\nstatic void\ndo_computation (gpointer user_data)\n{\n  \/\/ ...\n}<\/code><\/pre>\n<h2>Using GMainContext in a Library<\/h2>\n<blockquote>\n<p>At a high level, library code must not make changes to main contexts which could affect the execution of an application using the library, for example by changing when the application\u2019s sources are dispatched. There are various best practices which can be followed to aid this.<\/p>\n<p>Never iterate a context created outside the library, including the global-default or thread-default contexts. Otherwise, sources created in the application may be dispatched when the application is not expecting it, causing re-entrancy problems for the application code.<\/p>\n<\/blockquote>\n<p>\u4ece\u9ad8\u5c42\u6b21\u4e0a\u8bb2\uff0c\u5e93\u4ee3\u7801\u4e0d\u5f97\u5bf9\u4e3b\u4e0a\u4e0b\u6587\u8fdb\u884c\u66f4\u6539\uff0c\u56e0\u4e3a\u8fd9\u53ef\u80fd\u4f1a\u5f71\u54cd\u4f7f\u7528\u8be5\u5e93\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u6267\u884c\uff0c\u4f8b\u5982\u66f4\u6539\u5e94\u7528\u7a0b\u5e8f\u6e90\u7684\u8c03\u5ea6\u65f6\u95f4\u3002\u6709\u5404\u79cd\u6700\u4f73\u5b9e\u8df5\u53ef\u4ee5\u9075\u5faa\u4ee5\u534f\u52a9\u5b9e\u73b0\u8fd9\u4e00\u70b9\u3002<\/p>\n<p>\u5207\u52ff\u8fed\u4ee3\u4f7f\u7528\u5728\u5e93\u4ee5\u5916\u521b\u5efa\u7684\u4e0a\u4e0b\u6587(context)\uff0c\u5305\u62ec\u5168\u5c40\u9ed8\u8ba4(global-default)\u6216\u7ebf\u7a0b\u9ed8\u8ba4(thread-default)\u4e0a\u4e0b\u6587\u3002\u5426\u5219\uff0c\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u521b\u5efa\u7684\u6e90\u53ef\u80fd\u4f1a\u5728\u5e94\u7528\u7a0b\u5e8f\u4e0d\u671f\u671b\u65f6\u88ab\u8c03\u5ea6\uff0c\u4ece\u800c\u5bfc\u81f4\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\u7684\u91cd\u5165\u95ee\u9898\u3002<\/p>\n<blockquote>\n<p>Always remove sources from a main context before dropping the library\u2019s last reference to the context, especially if it may have been exposed to the application (for example, as a thread-default). Otherwise the application may keep a reference to the main context and continue iterating it after the library has returned, potentially causing unexpected source dispatches in the library. This is equivalent to not assuming that dropping the library\u2019s last reference to a main context will finalize that context.<\/p>\n<\/blockquote>\n<p>\u5728\u5220\u9664\u8f6f\u4ef6\u5e93\u5bf9\u4e0a\u4e0b\u6587\u7684\u6700\u540e\u4e00\u4e2a\u5f15\u7528\u4e4b\u524d\uff0c\u59cb\u7ec8\u8981\u5148\u4ece\u4e3b\u4e0a\u4e0b\u6587\u4e2d\u5220\u9664\u6e90(source)\uff0c\u7279\u522b\u662f\u5982\u679c\u5b83\u53ef\u80fd\u5df2\u66b4\u9732\u7ed9\u5e94\u7528\u7a0b\u5e8f\uff08\u4f8b\u5982\uff0c\u4f5c\u4e3a\u7ebf\u7a0b\u9ed8\u8ba4\uff09\u3002\u5426\u5219\uff0c\u5e94\u7528\u7a0b\u5e8f\u53ef\u80fd\u4f1a\u4fdd\u7559\u5bf9\u4e3b\u4e0a\u4e0b\u6587\u7684\u5f15\u7528\u5e76\u5728\u5e93\u8fd4\u56de\u540e\u7ee7\u7eed\u8fed\u4ee3\u5b83\uff0c\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u5e93\u4e2d\u51fa\u73b0\u610f\u5916\u7684\u6e90\u8c03\u5ea6\u3002\u8fd9\u76f8\u5f53\u4e8e\u4e0d\u5047\u8bbe\u5220\u9664\u5e93\u5bf9\u4e3b\u4e0a\u4e0b\u6587\u7684\u6700\u540e\u4e00\u4e2a\u5f15\u7528\u5c06\u5b8c\u6210\u8be5\u4e0a\u4e0b\u6587\u3002<\/p>\n<blockquote>\n<p>If the library is designed to be used from multiple threads, or in a context-aware fashion, always document which context each callback will be dispatched in. For example, \u201ccallbacks will always be dispatched in the context which is the thread-default at the time of the object\u2019s construction\u201d. Developers using the library\u2019s API need to know this information.<\/p>\n<\/blockquote>\n<p>\u5982\u679c\u5e93\u8bbe\u8ba1\u4e3a\u4ece\u591a\u4e2a\u7ebf\u7a0b\u4f7f\u7528\uff0c\u6216\u4ee5\u4e0a\u4e0b\u6587\u611f\u77e5\u7684\u65b9\u5f0f\u4f7f\u7528\uff0c\u5219\u59cb\u7ec8\u8bb0\u5f55\u6bcf\u4e2a\u56de\u8c03\u5c06\u5728\u54ea\u4e2a\u4e0a\u4e0b\u6587\u4e2d\u5206\u6d3e\u3002\u4f8b\u5982\uff0c\u201c\u56de\u8c03\u5c06\u59cb\u7ec8\u5728\u5bf9\u8c61\u6784\u9020\u65f6\u7684\u7ebf\u7a0b\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u4e2d\u5206\u6d3e\u201d\u3002\u4f7f\u7528\u5e93\u7684 API \u7684\u5f00\u53d1\u4eba\u5458\u9700\u8981\u77e5\u9053\u6b64\u4fe1\u606f\u3002<\/p>\n<blockquote>\n<p>Use g_main_context_invoke() to ensure callbacks are dispatched in the right context. It\u2019s much easier than manually using g_idle_source_new() to transfer work between contexts.<\/p>\n<p>Libraries should never use g_main_context_default() (or, equivalently, pass NULL to a GMainContext-typed parameter). Always store and explicitly use a specific GMainContext, even if it often points to some default context. This makes the code easier to split out into threads in future, if needed, without causing hard-to-debug problems caused by callbacks being invoked in the wrong context.<\/p>\n<\/blockquote>\n<p>\u4f7f\u7528 g_main_context_invoke() \u786e\u4fdd\u56de\u8c03\u5728\u6b63\u786e\u7684\u4e0a\u4e0b\u6587\u4e2d\u5206\u6d3e\u3002\u8fd9\u6bd4\u624b\u52a8\u4f7f\u7528 g_idle_source_new() \u5728\u4e0a\u4e0b\u6587\u4e4b\u95f4\u4f20\u8f93\u5de5\u4f5c\u8981\u5bb9\u6613\u5f97\u591a\u3002<\/p>\n<p>\u5e93\u6c38\u8fdc\u4e0d\u5e94\u4f7f\u7528 g_main_context_default()\uff08\u6216\u7b49\u6548\u5730\u5c06 NULL \u4f20\u9012\u7ed9 GMainContext \u7c7b\u578b\u7684\u53c2\u6570\uff09\u3002\u59cb\u7ec8\u5b58\u50a8\u5e76\u660e\u786e\u4f7f\u7528\u7279\u5b9a\u7684 GMainContext\uff0c\u5373\u4f7f\u5b83\u7ecf\u5e38\u6307\u5411\u67d0\u4e2a\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u3002\u8fd9\u4f7f\u5f97\u4ee3\u7801\u5728\u5c06\u6765\u66f4\u5bb9\u6613\u62c6\u5206\u6210\u7ebf\u7a0b\uff08\u5982\u679c\u9700\u8981\uff09\uff0c\u800c\u4e0d\u4f1a\u5bfc\u81f4\u7531\u4e8e\u5728\u9519\u8bef\u7684\u4e0a\u4e0b\u6587\u4e2d\u8c03\u7528\u56de\u8c03\u800c\u5bfc\u81f4\u96be\u4ee5\u8c03\u8bd5\u7684\u95ee\u9898\u3002<\/p>\n<blockquote>\n<p>Write things asynchronously internally (using GTask where appropriate), and keep synchronous wrappers at the very top level of an API, where they can be implemented by calling g_main_context_iteration() on a specific GMainContext. Again, this makes future refactoring easier. This is demonstrated in the previous example: the thread uses g_output_stream_write_async() rather than g_output_stream_write(). A worker thread may be used instead, and this can simplify the callback chain for long series of asynchronous calls; but at the cost of increased complexity in verifying the code is race-free.<\/p>\n<p>Always match pushes and pops of the thread-default main context: g_main_context_push_thread_default() and g_main_context_pop_thread_default().<\/p>\n<\/blockquote>\n<p>\u5728\u5185\u90e8\u5f02\u6b65\u5199\u5165\u5185\u5bb9\uff08\u5728\u9002\u5f53\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528 GTask\uff09\uff0c\u5e76\u5c06\u540c\u6b65\u5305\u88c5\u5668\u4fdd\u6301\u5728 API \u7684\u6700\u9876\u5c42\uff0c\u5728\u90a3\u91cc\u53ef\u4ee5\u901a\u8fc7\u5728\u7279\u5b9a GMainContext \u4e0a\u8c03\u7528 g_main_context_iteration() \u6765\u5b9e\u73b0\u5b83\u4eec\u3002\u540c\u6837\uff0c\u8fd9\u4f7f\u5f97\u672a\u6765\u7684\u91cd\u6784\u66f4\u5bb9\u6613\u3002\u8fd9\u5728\u524d\u9762\u7684\u793a\u4f8b\u4e2d\u5f97\u5230\u4e86\u6f14\u793a\uff1a\u7ebf\u7a0b\u4f7f\u7528 g_output_stream_write_async() \u800c\u4e0d\u662f g_output_stream_write()\u3002\u53ef\u4ee5\u4f7f\u7528\u5de5\u4f5c\u7ebf\u7a0b\u6765\u4ee3\u66ff\uff0c\u8fd9\u53ef\u4ee5\u7b80\u5316\u957f\u7cfb\u5217\u5f02\u6b65\u8c03\u7528\u7684\u56de\u8c03\u94fe\uff1b\u4f46\u4ee3\u4ef7\u662f\u589e\u52a0\u4e86\u9a8c\u8bc1\u4ee3\u7801\u662f\u5426\u65e0\u7ade\u4e89\u7684\u590d\u6742\u6027\u3002<\/p>\n<p>\u59cb\u7ec8\u5339\u914d\u7ebf\u7a0b\u9ed8\u8ba4\u4e3b\u4e0a\u4e0b\u6587\u7684\u63a8\u9001\u548c\u5f39\u51fa\uff1ag_main_context_push_thread_default() \u548c g_main_context_pop_thread_default()\u3002<\/p>\n<h2>Ensuring Functions are Called in the Right Context<\/h2>\n<p>\u786e\u4fdd\u5728\u6b63\u786e\u7684\u4e0a\u4e0b\u6587\u4e2d\u8c03\u7528\u51fd\u6570<\/p>\n<blockquote>\n<p>The \u2018right context\u2019 is the thread-default main context of the thread the function should be executing in. This assumes the typical case that every thread has a single main context running in a main loop. A main context effectively provides a work or message queue for the thread \u2014 something which the thread can periodically check to determine if there is work pending from another thread. Putting a message on this queue \u2013 invoking a function in another main context \u2013 will result in it eventually being dispatched in that thread.<\/p>\n<\/blockquote>\n<p>\u201c\u6b63\u786e\u7684\u4e0a\u4e0b\u6587\u201d\u662f\u51fd\u6570\u5e94\u5728\u5176\u4e2d\u6267\u884c\u7684\u7ebf\u7a0b\u7684\u7ebf\u7a0b\u9ed8\u8ba4\u4e3b\u4e0a\u4e0b\u6587\u3002\u8fd9\u5047\u8bbe\u5178\u578b\u60c5\u51b5\u662f\u6bcf\u4e2a\u7ebf\u7a0b\u90fd\u6709\u4e00\u4e2a\u5728\u4e3b\u5faa\u73af\u4e2d\u8fd0\u884c\u7684\u4e3b\u4e0a\u4e0b\u6587\u3002\u4e3b\u4e0a\u4e0b\u6587\u6709\u6548\u5730\u4e3a\u7ebf\u7a0b\u63d0\u4f9b\u4e86\u5de5\u4f5c\u6216\u6d88\u606f\u961f\u5217\u2014\u2014\u7ebf\u7a0b\u53ef\u4ee5\u5b9a\u671f\u68c0\u67e5\u4ee5\u786e\u5b9a\u662f\u5426\u6709\u6765\u81ea\u53e6\u4e00\u4e2a\u7ebf\u7a0b\u7684\u5f85\u5904\u7406\u5de5\u4f5c\u3002\u5c06\u6d88\u606f\u653e\u5728\u8fd9\u4e2a\u961f\u5217\u4e0a\u2014\u2014\u5728\u53e6\u4e00\u4e2a\u4e3b\u4e0a\u4e0b\u6587\u4e2d\u8c03\u7528\u4e00\u4e2a\u51fd\u6570\u2014\u2014\u6700\u7ec8\u5c06\u5bfc\u81f4\u5b83\u5728\u8be5\u7ebf\u7a0b\u4e2d\u88ab\u5206\u6d3e\u3002<\/p>\n<blockquote>\n<p>For example, if an application does a long and CPU-intensive computation it should schedule this in a background thread so that UI updates in the main thread are not blocked. The results of the computation, however, might need to be displayed in the UI, so some UI update function must be called in the main thread once the computation\u2019s complete.<\/p>\n<\/blockquote>\n<p>\u4f8b\u5982\uff0c\u5982\u679c\u5e94\u7528\u7a0b\u5e8f\u6267\u884c\u957f\u65f6\u95f4\u4e14 CPU \u5bc6\u96c6\u578b\u7684\u8ba1\u7b97\uff0c\u5219\u5e94\u5c06\u5176\u5b89\u6392\u5728\u540e\u53f0\u7ebf\u7a0b\u4e2d\uff0c\u4ee5\u4fbf\u4e3b\u7ebf\u7a0b\u4e2d\u7684 UI \u66f4\u65b0\u4e0d\u4f1a\u88ab\u963b\u6b62\u3002\u4f46\u662f\uff0c\u8ba1\u7b97\u7ed3\u679c\u53ef\u80fd\u9700\u8981\u663e\u793a\u5728 UI \u4e2d\uff0c\u56e0\u6b64\u4e00\u65e6\u8ba1\u7b97\u5b8c\u6210\uff0c\u5fc5\u987b\u5728\u4e3b\u7ebf\u7a0b\u4e2d\u8c03\u7528\u4e00\u4e9b UI \u66f4\u65b0\u51fd\u6570\u3002<\/p>\n<blockquote>\n<p>Furthermore, if the computation function can be limited to a single thread, it becomes easy to eliminate the need for locking a lot of the data it accesses. This assumes that other threads are implemented similarly and hence most data is only accessed by a single thread, with threads communicating by message passing. This allows each thread to update its data at its leisure, which significantly simplifies locking.<\/p>\n<\/blockquote>\n<p>\u6b64\u5916\uff0c\u5982\u679c\u8ba1\u7b97\u51fd\u6570\u53ef\u4ee5\u9650\u5236\u5728\u5355\u4e2a\u7ebf\u7a0b\u4e2d\uff0c\u90a3\u4e48\u5c31\u5f88\u5bb9\u6613\u6d88\u9664\u9501\u5b9a\u5b83\u8bbf\u95ee\u7684\u5927\u91cf\u6570\u636e\u7684\u9700\u8981\u3002\u8fd9\u5047\u8bbe\u5176\u4ed6\u7ebf\u7a0b\u7684\u5b9e\u73b0\u65b9\u5f0f\u7c7b\u4f3c\uff0c\u56e0\u6b64\u5927\u591a\u6570\u6570\u636e\u4ec5\u7531\u5355\u4e2a\u7ebf\u7a0b\u8bbf\u95ee\uff0c\u7ebf\u7a0b\u901a\u8fc7\u6d88\u606f\u4f20\u9012\u8fdb\u884c\u901a\u4fe1\u3002\u8fd9\u5141\u8bb8\u6bcf\u4e2a\u7ebf\u7a0b\u5728\u7a7a\u95f2\u65f6\u66f4\u65b0\u5176\u6570\u636e\uff0c\u4ece\u800c\u5927\u5927\u7b80\u5316\u9501\u5b9a\u3002<\/p>\n<blockquote>\n<p>For some functions, there might be no reason to care which context they\u2019re executed in, perhaps because they\u2019re asynchronous and hence do not block the context. However, it is still advisable to be explicit about which context is used, since those functions may emit signals or invoke callbacks, and for reasons of thread safety it\u2019s necessary to know which threads those signal handlers or callbacks are going to be invoked in.<\/p>\n<p>For example, the progress callback in g_file_copy_async() is documented as being called in the thread-default main context at the time of the initial call.<\/p>\n<\/blockquote>\n<p>\u5bf9\u4e8e\u67d0\u4e9b\u51fd\u6570\uff0c\u53ef\u80fd\u6ca1\u6709\u7406\u7531\u5173\u5fc3\u5b83\u4eec\u5728\u54ea\u4e2a\u4e0a\u4e0b\u6587\u4e2d\u6267\u884c\uff0c\u53ef\u80fd\u662f\u56e0\u4e3a\u5b83\u4eec\u662f\u5f02\u6b65\u7684\uff0c\u56e0\u6b64\u4e0d\u4f1a\u963b\u6b62\u4e0a\u4e0b\u6587\u3002\u4f46\u662f\uff0c\u4ecd\u7136\u5efa\u8bae\u660e\u786e\u4f7f\u7528\u54ea\u4e2a\u4e0a\u4e0b\u6587\uff0c\u56e0\u4e3a\u8fd9\u4e9b\u51fd\u6570\u53ef\u80fd\u4f1a\u53d1\u51fa\u4fe1\u53f7\u6216\u8c03\u7528\u56de\u8c03\uff0c\u5e76\u4e14\u51fa\u4e8e\u7ebf\u7a0b\u5b89\u5168\u7684\u539f\u56e0\uff0c\u6709\u5fc5\u8981\u77e5\u9053\u5c06\u5728\u54ea\u4e9b\u7ebf\u7a0b\u4e2d\u8c03\u7528\u8fd9\u4e9b\u4fe1\u53f7\u5904\u7406\u7a0b\u5e8f\u6216\u56de\u8c03\u3002<\/p>\n<p>\u4f8b\u5982\uff0cg_file_copy_async() \u4e2d\u7684\u8fdb\u5ea6\u56de\u8c03\u88ab\u8bb0\u5f55\u4e3a\u5728\u521d\u59cb\u8c03\u7528\u65f6\u5728\u7ebf\u7a0b\u9ed8\u8ba4\u4e3b\u4e0a\u4e0b\u6587\u4e2d\u8c03\u7528\u3002<\/p>\n<h2>Principles of Invocation<\/h2>\n<p>\u8c03\u7528\u539f\u5219<\/p>\n<blockquote>\n<p>The core principle of invoking a function in a specific context is simple, and is walked through below to explain the concepts. In practice the convenience method, g_main_context_invoke_full() should be used instead.<\/p>\n<\/blockquote>\n<p>\u5728\u7279\u5b9a\u4e0a\u4e0b\u6587\u4e2d\u8c03\u7528\u51fd\u6570\u7684\u6838\u5fc3\u539f\u5219\u5f88\u7b80\u5355\uff0c\u4e0b\u9762\u5c06\u9010\u6b65\u4ecb\u7ecd\u8fd9\u4e9b\u6982\u5ff5\u3002\u5728\u5b9e\u8df5\u4e2d\uff0c\u5e94\u6539\u7528\u4fbf\u6377\u65b9\u6cd5 g_main_context_invoke_full()\u3002<\/p>\n<blockquote>\n<p>A GSource has to be added to the target GMainContext, which will invoke the function when it\u2019s dispatched. This GSource should almost always be an idle source created with g_idle_source_new(), but this doesn\u2019t have to be the case. It could be a timeout source so that the function is executed after a delay, for example.<\/p>\n<\/blockquote>\n<p>\u5fc5\u987b\u5c06 GSource \u6dfb\u52a0\u5230\u76ee\u6807 GMainContext\uff0c\u5b83\u5c06\u5728\u5206\u6d3e\u65f6\u8c03\u7528\u8be5\u51fd\u6570\u3002\u6b64 GSource \u51e0\u4e4e\u59cb\u7ec8\u662f\u4f7f\u7528 g_idle_source_new() \u521b\u5efa\u7684\u7a7a\u95f2\u6e90\uff0c\u4f46\u4e0d\u4e00\u5b9a\u5982\u6b64\u3002\u4f8b\u5982\uff0c\u5b83\u53ef\u4ee5\u662f\u8d85\u65f6\u6e90\uff0c\u4ee5\u4fbf\u51fd\u6570\u5728\u5ef6\u8fdf\u540e\u6267\u884c\u3002<\/p>\n<blockquote>\n<p>The GSource will be dispatched as soon as it\u2019s ready, calling the function on the thread\u2019s stack. In the case of an idle source, this will be as soon as all sources at a higher priority have been dispatched \u2014 this can be tweaked using the idle source\u2019s priority parameter with g_source_set_priority(). The source will typically then be destroyed so the function is only executed once (though again, this doesn\u2019t have to be the case).<\/p>\n<\/blockquote>\n<p>GSource \u5c06\u5728\u51c6\u5907\u5c31\u7eea\u540e\u7acb\u5373\u5206\u6d3e\uff0c\u5e76\u5728\u7ebf\u7a0b\u5806\u6808\u4e0a\u8c03\u7528\u8be5\u51fd\u6570\u3002\u5bf9\u4e8e\u7a7a\u95f2\u6e90\uff0c\u8fd9\u5c06\u5728\u66f4\u9ad8\u4f18\u5148\u7ea7\u7684\u6240\u6709\u6e90\u90fd\u5df2\u5206\u6d3e\u540e\u7acb\u5373\u8fdb\u884c \u2014 \u53ef\u4ee5\u4f7f\u7528\u7a7a\u95f2\u6e90\u7684\u4f18\u5148\u7ea7\u53c2\u6570\u548c g_source_set_priority() \u8fdb\u884c\u8c03\u6574\u3002\u7136\u540e\u901a\u5e38\u4f1a\u9500\u6bc1\u6e90\uff0c\u4ee5\u4fbf\u51fd\u6570\u4ec5\u6267\u884c\u4e00\u6b21\uff08\u4f46\u540c\u6837\uff0c\u4e0d\u4e00\u5b9a\u5982\u6b64\uff09\u3002<\/p>\n<blockquote>\n<p>Data can be passed between threads as the user_data passed to the GSource\u2019s callback. This is set on the source using g_source_set_callback(), along with the callback function to invoke. Only a single pointer is provided, so if multiple data fields need passing, they must be wrapped in an allocated structure.<\/p>\n<\/blockquote>\n<p>\u6570\u636e\u53ef\u4ee5\u5728\u7ebf\u7a0b\u4e4b\u95f4\u4f20\u9012\uff0c\u56e0\u4e3a user_data \u4f1a\u4f20\u9012\u7ed9 GSource \u7684\u56de\u8c03\u3002\u8fd9\u662f\u4f7f\u7528 g_source_set_callback() \u5728\u6e90\u4e0a\u8bbe\u7f6e\u7684\uff0c\u4ee5\u53ca\u8981\u8c03\u7528\u7684\u56de\u8c03\u51fd\u6570\u3002\u53ea\u63d0\u4f9b\u4e86\u4e00\u4e2a\u6307\u9488\uff0c\u56e0\u6b64\u5982\u679c\u9700\u8981\u4f20\u9012\u591a\u4e2a\u6570\u636e\u5b57\u6bb5\uff0c\u5219\u5fc5\u987b\u5c06\u5b83\u4eec\u5305\u88c5\u5728\u5206\u914d\u7684\u7ed3\u6784\u4e2d\u3002<\/p>\n<p>\u4e0b\u9762\u7684\u793a\u4f8b\u6f14\u793a\u4e86\u5e95\u5c42\u539f\u7406\uff0c\u4f46\u4e0b\u9762\u89e3\u91ca\u4e86\u4e00\u4e9b\u7b80\u4fbf\u7684\u65b9\u6cd5\uff0c\u53ef\u4ee5\u7b80\u5316\u4e8b\u60c5\u3002<\/p>\n<pre><code class=\"language-c\">\/* Main function for the background thread, thread1. *\/\nstatic gpointer\nthread1_main (gpointer user_data)\n{\n  GMainContext *thread1_main_context = user_data;\n  GMainLoop *main_loop;\n\n  \/* Set up the thread\u2019s context and run it forever. *\/\n  g_main_context_push_thread_default (thread1_main_context);\n\n  main_loop = g_main_loop_new (thread1_main_context, FALSE);\n  g_main_loop_run (main_loop);\n  g_main_loop_unref (main_loop);\n\n  g_main_context_pop_thread_default (thread1_main_context);\n  g_main_context_unref (thread1_main_context);\n\n  return NULL;\n}\n\n\/* A data closure structure to carry multiple variables between\n * threads. *\/\ntypedef struct {\n  gchar   *some_string;  \/* owned *\/\n  guint    some_int;\n  GObject *some_object;  \/* owned *\/\n} MyFuncData;\n\nstatic void\nmy_func_data_free (MyFuncData *data)\n{\n  g_free (data-&gt;some_string);\n  g_clear_object (&amp;data-&gt;some_object);\n  g_free (data);\n}\n\nstatic void\nmy_func (const gchar *some_string,\n         guint        some_int,\n         GObject     *some_object)\n{\n  \/* Do something long and CPU intensive! *\/\n}\n\n\/* Convert an idle callback into a call to my_func(). *\/\nstatic gboolean\nmy_func_idle (gpointer user_data)\n{\n  MyFuncData *data = user_data;\n\n  my_func (data-&gt;some_string, data-&gt;some_int, data-&gt;some_object);\n\n  return G_SOURCE_REMOVE;\n}\n\n\/* Function to be called in the main thread to schedule a call to\n * my_func() in thread1, passing the given parameters along. *\/\nstatic void\ninvoke_my_func (GMainContext *thread1_main_context,\n                const gchar  *some_string,\n                guint         some_int,\n                GObject      *some_object)\n{\n  GSource *idle_source;\n  MyFuncData *data;\n\n  \/* Create a data closure to pass all the desired variables\n   * between threads. *\/\n  data = g_new0 (MyFuncData, 1);\n  data-&gt;some_string = g_strdup (some_string);\n  data-&gt;some_int = some_int;\n  data-&gt;some_object = g_object_ref (some_object);\n\n  \/* Create a new idle source, set my_func() as the callback with\n   * some data to be passed between threads, bump up the priority\n   * and schedule it by attaching it to thread1\u2019s context. *\/\n  idle_source = g_idle_source_new ();\n  g_source_set_callback (idle_source, my_func_idle, data,\n                         (GDestroyNotify) my_func_data_free);\n  g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);\n  g_source_attach (idle_source, thread1_main_context);\n  g_source_unref (idle_source);\n}\n\n\/* Main function for the main thread. *\/\nstatic void\nmain (void)\n{\n  GThread *thread1;\n  GMainContext *thread1_main_context;\n\n  \/* Spawn a background thread and pass it a reference to its\n   * GMainContext. Retain a reference for use in this thread\n   * too. *\/\n  thread1_main_context = g_main_context_new ();\n  g_thread_new (&quot;thread1&quot;, thread1_main,\n                g_main_context_ref (thread1_main_context));\n\n  \/* Maybe set up your UI here, for example. *\/\n\n  \/* Invoke my_func() in the other thread. *\/\n  invoke_my_func (thread1_main_context,\n                  &quot;some data which needs passing between threads&quot;,\n                  123456, some_object);\n\n  \/* Continue doing other work. *\/\n}\n<\/code><\/pre>\n<p>\u6b64\u8c03\u7528\u662f\u5355\u5411\u7684\uff1a\u5b83\u5728\u7ebf\u7a0b 1 \u4e2d\u8c03\u7528 my_func()\uff0c\u4f46\u65e0\u6cd5\u5c06\u503c\u8fd4\u56de\u7ed9\u4e3b\u7ebf\u7a0b\u3002\u4e3a\u6b64\uff0c\u9700\u8981\u518d\u6b21\u4f7f\u7528\u76f8\u540c\u7684\u539f\u7406\uff0c\u5728\u4e3b\u7ebf\u7a0b\u4e2d\u8c03\u7528\u56de\u8c03\u51fd\u6570\u3002\u8fd9\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u6269\u5c55\uff0c\u672c\u6587\u4e0d\u4f5c\u4ecb\u7ecd\u3002<\/p>\n<p>\u4e3a\u4e86\u4fdd\u6301\u7ebf\u7a0b\u5b89\u5168\uff0c\u53ef\u80fd\u88ab\u591a\u4e2a\u7ebf\u7a0b\u8bbf\u95ee\u7684\u6570\u636e\u5fc5\u987b\u4f7f\u7528\u4e92\u65a5\u9501\u4f7f\u8fd9\u4e9b\u8bbf\u95ee\u4e92\u65a5\u3002\u53ef\u80fd\u88ab\u591a\u4e2a\u7ebf\u7a0b\u8bbf\u95ee\u7684\u6570\u636e\uff1athread1_main_context\uff0c\u5728\u5bf9 thread1_main \u7684 fork \u8c03\u7528\u4e2d\u4f20\u9012\uff1bsome_object\uff0c\u5728\u6570\u636e\u95ed\u5305\u4e2d\u4f20\u9012\u5bf9\u5176\u7684\u5f15\u7528\u3002\u81f3\u5173\u91cd\u8981\u7684\u662f\uff0cGLib \u4fdd\u8bc1 GMainContext \u662f\u7ebf\u7a0b\u5b89\u5168\u7684\uff0c\u56e0\u6b64\u5728\u7ebf\u7a0b\u4e4b\u95f4\u5171\u4eab thread1_main_context \u662f\u5b89\u5168\u7684\u3002\u8be5\u793a\u4f8b\u5047\u8bbe\u8bbf\u95ee some_object \u7684\u5176\u4ed6\u4ee3\u7801\u662f\u7ebf\u7a0b\u5b89\u5168\u7684\u3002<\/p>\n<p>\u8bf7\u6ce8\u610f\uff0csome_string \u548c some_int \u4e0d\u80fd\u4ece\u4e24\u4e2a\u7ebf\u7a0b\u8bbf\u95ee\uff0c\u56e0\u4e3a\u5b83\u4eec\u7684\u526f\u672c\u800c\u4e0d\u662f\u539f\u59cb\u526f\u672c\u88ab\u4f20\u9012\u7ed9\u7ebf\u7a0b 1\u3002\u8fd9\u662f\u4e00\u79cd\u4f7f\u8de8\u7ebf\u7a0b\u8c03\u7528\u7ebf\u7a0b\u5b89\u5168\u800c\u65e0\u9700\u9501\u5b9a\u7684\u6807\u51c6\u6280\u672f\u3002\u5b83\u8fd8\u907f\u514d\u4e86\u540c\u6b65\u91ca\u653e some_string \u7684\u95ee\u9898\u3002<\/p>\n<p>\u7c7b\u4f3c\u5730\uff0c\u5bf9 some_object \u7684\u5f15\u7528\u88ab\u8f6c\u79fb\u5230\u7ebf\u7a0b 1\uff0c\u8fd9\u89e3\u51b3\u4e86\u540c\u6b65\u9500\u6bc1\u5bf9\u8c61\u7684\u95ee\u9898\u3002<\/p>\n<p>\u4f7f\u7528 g_idle_source_new() \u800c\u4e0d\u662f\u66f4\u7b80\u5355\u7684 g_idle_add()\uff0c\u56e0\u6b64\u53ef\u4ee5\u6307\u5b9a\u8981\u9644\u52a0\u5230\u7684 GMainContext\u3002<\/p>\n<h2>Convenience Method: g_main_context_invoke_full()<\/h2>\n<p>This is simplified greatly by the convenience method, g_main_context_invoke_full(). It invokes a callback so that the specified GMainContext is owned during the invocation. Owning a main context is almost always equivalent to running it, and hence the function is invoked in the thread for which the specified context is the thread-default.<\/p>\n<p>g_main_context_invoke() can be used instead if the user data does not need to be freed by a GDestroyNotify callback after the invocation returns.<\/p>\n<p>Modifying the earlier example, the invoke_my_func() function can be replaced by the following:<\/p>\n<h2>Summary<\/h2>\n<ul>\n<li>\n<p>Use g_main_context_invoke_full() to invoke functions in other threads, assuming every thread has a thread default main context which runs throughout the lifetime of that thread<\/p>\n<\/li>\n<li>\n<p>Use GTask to run a function in the background without caring about the specific thread used<\/p>\n<\/li>\n<li>\n<p>Liberally use assertions to check which context executes each function, and add these assertions when first writing the code<\/p>\n<\/li>\n<li>\n<p>Explicitly document contexts a function is expected to be called in, a callback will be invoked in, or a signal will be emitted in<\/p>\n<\/li>\n<li>\n<p>Beware of g_idle_add() and similar functions which implicitly use the global-default main context<\/p>\n<\/li>\n<\/ul>\n<h2>Reference<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.gtk.org\/glib\/running.html\">https:\/\/docs.gtk.org\/glib\/running.html<\/a><\/li>\n<li><a href=\"https:\/\/docs.gtk.org\/glib\/threads.html\">https:\/\/docs.gtk.org\/glib\/threads.html<\/a><\/li>\n<li><a href=\"https:\/\/docs.gtk.org\/glib\/main-loop.html\">https:\/\/docs.gtk.org\/glib\/main-loop.html<\/a><\/li>\n<li><a href=\"https:\/\/developer.gnome.org\/documentation\/tutorials\/main-contexts.html#using-gmaincontext-in-a-library\">https:\/\/developer.gnome.org\/documentation\/tutorials\/main-contexts.html#using-gmaincontext-in-a-library<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>GLib is a general-purpose, portable utility library, which provides many useful data types, macros, type conversions, string utilities, file utilities, a mainloop abstraction, and so on. \u5728 Linux \u7cfb\u7edf\u4e0a\u505a C\/C++ \u8bed\u8a00\u7684\u5f00\u53d1, glib \u662f\u5e38\u7528\u7684 library, \u5927\u91cf\u7684\u7684 library \u4e5f\u57fa\u4e8e\u5b83, \u4f8b\u5982 gstreamer, libsoup \u7b49\u5927\u540d\u9f0e\u9f0e\u7684\u5de5\u5177\u548c\u5e93. What is GMainContext? GMainContext is a generalized implementation of an event loop, useful for [&hellip;] <a class=\"read-more\" href=\"https:\/\/www.fanyamin.com\/wordpress\/?p=1463\" title=\"Permanent Link to: glib\u4e2d\u7684\u9677\u9631\">&rarr;Read&nbsp;more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-1463","post","type-post","status-publish","format-standard","hentry","category-5"],"_links":{"self":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1463"}],"collection":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1463"}],"version-history":[{"count":9,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1463\/revisions"}],"predecessor-version":[{"id":1472,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1463\/revisions\/1472"}],"wp:attachment":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}