/usr/share/help/de/programming-guidelines/main-contexts.page is in gnome-devel-docs 3.28.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | <?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2003/XInclude" type="topic" id="main-contexts" xml:lang="de">
<info>
<link type="guide" xref="index#specific-how-tos"/>
<credit type="author copyright">
<name>Philip Withnall</name>
<email its:translate="no">philip.withnall@collabora.co.uk</email>
<years>2014–2015</years>
</credit>
<include xmlns="http://www.w3.org/2001/XInclude" href="cc-by-sa-3-0.xml"/>
<desc>
GLib main contexts, invoking functions in other threads, and the event
loop
</desc>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>Mario Blättermann</mal:name>
<mal:email>mario.blaettermann@gmail.com</mal:email>
<mal:years>2016</mal:years>
</mal:credit>
<mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
<mal:name>Christian Kirbach</mal:name>
<mal:email>christian.kirbach@gmail.com</mal:email>
<mal:years>2016</mal:years>
</mal:credit>
</info>
<title>GLib Main Contexts</title>
<synopsis>
<title>Zusammenfassung</title>
<list>
<item><p>
Use
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-main-context-invoke-full"><code>g_main_context_invoke_full()</code></link>
to invoke functions in other threads, assuming every thread has a thread
default main context which runs throughout the lifetime of that thread
(<link xref="#g-main-context-invoke-full"/>)
</p></item>
<item><p>
Use
<link href="https://developer.gnome.org/gio/stable/GTask.html"><code>GTask</code></link>
to run a function in the background without caring about the specific
thread used (<link xref="#gtask"/>)
</p></item>
<item><p>
Liberally use assertions to check which context executes each function,
and add these assertions when first writing the code
(<link xref="#checking-threading"/>)
</p></item>
<item><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
(<link xref="#using-gmaincontext-in-a-library"/>)
</p></item>
<item><p>
Beware of <code>g_idle_add()</code> and similar functions which
implicitly use the global-default main context
(<link xref="#implicit-use-of-the-global-default-main-context"/>)
</p></item>
</list>
</synopsis>
<section id="what-is-gmaincontext">
<title>Was ist <code>GMainContext</code>?</title>
<p>
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GMainContext"><code>GMainContext</code></link>
is a generalized implementation of an
<link href="http://en.wikipedia.org/wiki/Event_loop">event loop</link>,
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 <code>GMainContext</code> requires understanding
<link href="man:poll(2)">poll()</link> and polled I/O.
</p>
<p>
A <code>GMainContext</code> has a set of
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSource"><code>GSource</code></link>s
which are ‘attached’ 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. One iteration of the event loop will:
</p>
<list type="enumerated">
<item><p>
Prepare sources, determining if any of them are ready to dispatch
immediately.
</p></item>
<item><p>
Poll the sources, blocking the current thread until an event is received
for one of the sources.
</p></item>
<item><p>
Check which of the sources received an event (several could have).
</p></item>
<item><p>
Dispatch callbacks from those sources.
</p></item>
</list>
<p>
This is
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#mainloop-states">explained
very well</link> in the
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSourceFuncs">GLib
documentation</link>.
</p>
<p>
At its core, <code>GMainContext</code> is just a <code>poll()</code> loop,
with the preparation, check and dispatch stages of the loop corresponding
to the normal preamble and postamble in a typical <code>poll()</code> loop
implementation, such as listing 1 from
<link href="http://www.linux-mag.com/id/357/">this article</link>.
Typically, some complexity is needed in non-trivial
<code>poll()</code>-using applications to track the lists of FDs which are
being polled. Additionally, <code>GMainContext</code> adds a lot of useful
functionality which vanilla <code>poll()</code> doesn’t support. Most
importantly, it adds thread safety.
</p>
<p>
<code>GMainContext</code> is completely thread safe, meaning that a
<code>GSource</code> can be created in one thread and attached to a
<code>GMainContext</code> running in another thread. (See
also: <link xref="threading"/>.) A typical use for this might be to allow
worker threads to control which sockets are being listened to by a
<code>GMainContext</code> in a central I/O thread. Each
<code>GMainContext</code> is ‘acquired’ by a thread for each iteration
it’s put through. Other threads cannot iterate a <code>GMainContext</code>
without acquiring it, which guarantees that a <code>GSource</code> and its
FDs will only be polled by one thread at once (since each
<code>GSource</code> is attached to at most one
<code>GMainContext</code>). A <code>GMainContext</code> can be swapped
between threads across iterations, but this is expensive.
</p>
<p>
<code>GMainContext</code> is used instead of <code>poll()</code> mostly
for convenience, as it transparently handles dynamically managing
the array of FDs to pass to <code>poll()</code>, especially when operating
over multiple threads. This is done by encapsulating FDs in
<code>GSource</code>s, which decide whether those FDs should be passed to
the <code>poll()</code> call on each ‘prepare’ stage of the main context
iteration.
</p>
</section>
<section id="what-is-gmainloop">
<title>Was ist <code>GMainLoop</code>?</title>
<p>
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GMainLoop"><code>GMainLoop</code></link>
is essentially the following few lines of code, once reference counting
and locking have been removed (from
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-main-loop-run"><code>g_main_loop_run()</code></link>):
</p>
<code mime="text/x-csrc">loop->is_running = TRUE;
while (loop->is_running)
{
g_main_context_iteration (context, TRUE);
}</code>
<p>
Plus a fourth line in
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-main-loop-quit"><code>g_main_loop_quit()</code></link>
which sets <code>loop->is_running = FALSE</code> and which will cause
the loop to terminate once the current main context iteration ends.
</p>
<p>
Hence, <code>GMainLoop</code> is a convenient, thread-safe way of running
a <code>GMainContext</code> to process events until a desired exit
condition is met, at which point <code>g_main_loop_quit()</code> should be
called. Typically, in a UI program, this will be the user clicking ‘exit’.
In a socket handling program, this might be the final socket closing.
</p>
<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>
</section>
<section id="default-contexts">
<title>Default Contexts</title>
<p>
One of the important features of <code>GMainContext</code> is its support
for ‘default’ contexts. There are two levels of default context: the
thread-default, and the global-default. The global-default (accessed using
<code>g_main_context_default()</code>) is run by GTK+ when
<code>gtk_main()</code> is called. It’s also used for timeouts
(<code>g_timeout_add()</code>) and idle callbacks
(<code>g_idle_add()</code>) — these won’t be dispatched unless the default
context is running! (See:
<link xref="#implicit-use-of-the-global-default-main-context"/>.)
</p>
<p>
Thread-default contexts are a later addition to GLib (since version 2.22),
and are generally used for I/O operations which need to run and dispatch
callbacks in a thread. By calling
<code>g_main_context_push_thread_default()</code> 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’s 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
<code>GMainContext</code> pointer around everywhere.
</p>
<p>
Conversely, by starting a long-running operation with a specific
thread-default context set, the calling code can guarantee that the
operation’s callbacks will be emitted in that context, even if the
operation itself runs in a worker thread. This is the principle behind
<link href="https://developer.gnome.org/gio/stable/GTask.html"><code>GTask</code></link>:
when a new <code>GTask</code> 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
<link href="https://developer.gnome.org/gio/stable/GTask.html#g-task-run-in-thread"><code>g_task_run_in_thread()</code></link>.
</p>
<example>
<p>
For example, the code below will run a <code>GTask</code> 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 <code>interesting_context</code>.
</p>
<code mime="text/x-csrc" style="valid">
typedef struct {
GMainLoop *main_loop;
guint n_remaining;
} WriteData;
/* This is always called in the same thread as thread_cb() because
* it’s always dispatched in the @worker_context. */
static void
write_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
WriteData *data = user_data;
GOutputStream *stream = G_OUTPUT_STREAM (source_object);
GError *error = NULL;
gssize len;
/* Finish the write. */
len = g_output_stream_write_finish (stream, result, &error);
if (error != NULL)
{
g_error ("Error: %s", error->message);
g_error_free (error);
}
/* Check whether all parallel operations have finished. */
write_data->n_remaining--;
if (write_data->n_remaining == 0)
{
g_main_loop_quit (write_data->main_loop);
}
}
/* This is called in a new thread. */
static void
thread_cb (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
/* These streams come from somewhere else in the program: */
GOutputStream *output_stream1, *output_stream;
GMainContext *worker_context;
GBytes *data;
const guint8 *buf;
gsize len;
/* Set up a worker context for the writes’ callbacks. */
worker_context = g_main_context_new ();
g_main_context_push_thread_default (worker_context);
/* Set up the writes. */
write_data.n_remaining = 2;
write_data.main_loop = g_main_loop_new (worker_context, FALSE);
data = g_task_get_task_data (task);
buf = g_bytes_get_data (data, &len);
g_output_stream_write_async (output_stream1, buf, len,
G_PRIORITY_DEFAULT, NULL, write_cb,
&write_data);
g_output_stream_write_async (output_stream2, buf, len,
G_PRIORITY_DEFAULT, NULL, write_cb,
&write_data);
/* Run the main loop until both writes have finished. */
g_main_loop_run (write_data.main_loop);
g_task_return_boolean (task, TRUE); /* ignore errors */
g_main_loop_unref (write_data.main_loop);
g_main_context_pop_thread_default (worker_context);
g_main_context_unref (worker_context);
}
/* This can be called from any thread. Its @callback will always be
* dispatched in the thread which currently owns
* @interesting_context. */
void
parallel_writes_async (GBytes *data,
GMainContext *interesting_context,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
g_main_context_push_thread_default (interesting_context);
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_task_data (task, data,
(GDestroyNotify) g_bytes_unref);
g_task_run_in_thread (task, thread_cb);
g_object_unref (task);
g_main_context_pop_thread_default (interesting_context);
}</code>
</example>
<section id="implicit-use-of-the-global-default-main-context">
<title>Implicit Use of the Global-Default Main Context</title>
<p>
Several functions implicitly add sources to the global-default main
context. They should <em>not</em> be used in threaded code. Instead, use
<code>g_source_attach()</code> with the <code>GSource</code> created by
the replacement function from the table below.
</p>
<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>
<table shade="rows">
<colgroup><col/></colgroup>
<colgroup><col/><col/></colgroup>
<thead>
<tr>
<td><p>Verwenden sie nicht</p></td>
<td><p>sondern stattdessen</p></td>
</tr>
</thead>
<tbody>
<tr>
<td><p><code>g_timeout_add()</code></p></td>
<td><p><code>g_timeout_source_new()</code></p></td>
</tr>
<tr>
<td><p><code>g_idle_add()</code></p></td>
<td><p><code>g_idle_source_new()</code></p></td>
</tr>
<tr>
<td><p><code>g_child_watch_add()</code></p></td>
<td><p><code>g_child_watch_source_new()</code></p></td>
</tr>
</tbody>
</table>
<example>
<p>
So to delay some computation in a worker thread, use the following
code:
</p>
<code mime="text/x-csrc">
static guint
schedule_computation (guint delay_seconds)
{
GSource *source = NULL;
GMainContext *context;
guint id;
/* Get the calling context. */
context = g_main_context_get_thread_default ();
source = g_timeout_source_new_seconds (delay_seconds);
g_source_set_callback (source, do_computation, NULL, NULL);
id = g_source_attach (source, context);
g_source_unref (source);
/* The ID can be used with the same @context to
* cancel the scheduled computation if needed. */
return id;
}
static void
do_computation (gpointer user_data)
{
/* … */
}</code>
</example>
</section>
</section>
<section id="using-gmaincontext-in-a-library">
<title>Verwendung von <code>GMainContext</code> in einer Bibliothek</title>
<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’s <code>GSource</code>s are
dispatched. There are various best practices which can be followed to aid
this.
</p>
<p>
Never iterate a context created outside the library, including the
global-default or thread-default contexts. Otherwise,
<code>GSource</code>s created in the application may be dispatched
when the application is not expecting it, causing
<link href="http://en.wikipedia.org/wiki/Reentrancy_%28computing%29">re-entrancy
problems</link> for the application code.
</p>
<p>
Always remove <code>GSource</code>s from a main context before dropping
the library’s 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’s last reference to a main context will
finalize that context.
</p>
<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, “callbacks will always be dispatched in the
context which is the thread-default at the time of the object’s
construction”. Developers using the library’s API need to know this
information.
</p>
<p>
Use <code>g_main_context_invoke()</code> to ensure callbacks are
dispatched in the right context. It’s much easier than manually using
<code>g_idle_source_new()</code> to transfer work between contexts.
(See: <link xref="#ensuring-functions-are-called-in-the-right-context"/>.)
</p>
<p>
Libraries should never use <code>g_main_context_default()</code> (or,
equivalently, pass <code>NULL</code> to a <code>GMainContext</code>-typed
parameter). Always store and explicitly use a specific
<code>GMainContext</code>, 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>
<p>
Always write things asynchronously internally (using
<link xref="#gtask"><code>GTask</code></link> where appropriate), and keep
synchronous wrappers at the very top level of an API, where they can be
implemented by calling <code>g_main_context_iteration()</code> on a
specific <code>GMainContext</code>. Again, this makes future refactoring
easier. This is demonstrated in the above example: the thread uses
<code>g_output_stream_write_async()</code> rather than
<code>g_output_stream_write()</code>.
</p>
<p>
Always match pushes and pops of the thread-default main context:
<code>g_main_context_push_thread_default()</code> and
<code>g_main_context_pop_thread_default()</code>.
</p>
</section>
<section id="ensuring-functions-are-called-in-the-right-context">
<title>Ensuring Functions are Called in the Right Context</title>
<p>
The ‘right context’ is the thread-default main context of the <em>thread
the function should be executing in</em>. This assumes the typical case
that every thread has a <em>single</em> main context running in a main
loop. A main context effectively provides a work or
<link href="http://en.wikipedia.org/wiki/Message_queue">message
queue</link> for the thread — something which the thread can
periodically check to determine if there is work pending from
another thread. Putting a message on this queue – invoking a function in
another main context – will result in it eventually being dispatched in
that thread.
</p>
<example>
<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’s complete.
</p>
<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
<link href="http://en.wikipedia.org/wiki/Message_passing">message
passing</link>. This allows each thread to update its data at its
leisure, which significantly simplifies locking.
</p>
</example>
<p>
For some functions, there might be no reason to care which context they’re
executed in, perhaps because they’re 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’s necessary to know which
threads those signal handlers or callbacks are going to be invoked in.
</p>
<example>
<p>
For example, the progress callback in
<link href="https://developer.gnome.org/gio/stable/GFile.html#g-file-copy-async"><code>g_file_copy_async()</code></link>
is documented as being called in the thread-default main context
at the time of the initial call.
</p>
</example>
<section id="invocation-core-principle">
<title>Principles of Invocation</title>
<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 <link xref="#g-main-context-invoke-full">convenience method,
<code>g_main_context_invoke_full()</code></link> should be used instead.
</p>
<p>
A
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSource"><code>GSource</code></link>
has to be added to the target <code>GMainContext</code>, which will invoke
the function when it’s dispatched. This <code>GSource</code> should almost
always be an idle source created with
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-idle-source-new"><code>g_idle_source_new()</code></link>,
but this doesn’t have to be the case. It could be a timeout source
so that the function is executed after a delay, for example.
</p>
<p>
The <code>GSource</code> will be
<link xref="#what-is-gmaincontext">dispatched as soon as it’s ready</link>,
calling the function on the thread’s stack. In the case of an idle source,
this will be as soon as all sources at a higher priority have been
dispatched — this can be tweaked using the idle source’s priority
parameter with
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-source-set-priority"><code>g_source_set_priority()</code></link>.
The source will typically then be destroyed so the function is only
executed once (though again, this doesn’t have to be the case).
</p>
<p>
Data can be passed between threads as the <code>user_data</code> passed to
the <code>GSource</code>’s callback. This is set on the source using
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-source-set-callback"><code>g_source_set_callback()</code></link>,
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>
<example>
<p>
The example below demonstrates the underlying principles, but there are
convenience methods explained below which simplify things.
</p>
<code mime="text/x-csrc">
/* Main function for the background thread, thread1. */
static gpointer
thread1_main (gpointer user_data)
{
GMainContext *thread1_main_context = user_data;
GMainLoop *main_loop;
/* Set up the thread’s context and run it forever. */
g_main_context_push_thread_default (thread1_main_context);
main_loop = g_main_loop_new (thread1_main_context, FALSE);
g_main_loop_run (main_loop);
g_main_loop_unref (main_loop);
g_main_context_pop_thread_default (thread1_main_context);
g_main_context_unref (thread1_main_context);
return NULL;
}
/* A data closure structure to carry multiple variables between
* threads. */
typedef struct {
gchar *some_string; /* owned */
guint some_int;
GObject *some_object; /* owned */
} MyFuncData;
static void
my_func_data_free (MyFuncData *data)
{
g_free (data->some_string);
g_clear_object (&data->some_object);
g_free (data);
}
static void
my_func (const gchar *some_string,
guint some_int,
GObject *some_object)
{
/* Do something long and CPU intensive! */
}
/* Convert an idle callback into a call to my_func(). */
static gboolean
my_func_idle (gpointer user_data)
{
MyFuncData *data = user_data;
my_func (data->some_string, data->some_int, data->some_object);
return G_SOURCE_REMOVE;
}
/* Function to be called in the main thread to schedule a call to
* my_func() in thread1, passing the given parameters along. */
static void
invoke_my_func (GMainContext *thread1_main_context,
const gchar *some_string,
guint some_int,
GObject *some_object)
{
GSource *idle_source;
MyFuncData *data;
/* Create a data closure to pass all the desired variables
* between threads. */
data = g_new0 (MyFuncData, 1);
data->some_string = g_strdup (some_string);
data->some_int = some_int;
data->some_object = g_object_ref (some_object);
/* Create a new idle source, set my_func() as the callback with
* some data to be passed between threads, bump up the priority
* and schedule it by attaching it to thread1’s context. */
idle_source = g_idle_source_new ();
g_source_set_callback (idle_source, my_func_idle, data,
(GDestroyNotify) my_func_data_free);
g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
g_source_attach (idle_source, thread1_main_context);
g_source_unref (idle_source);
}
/* Main function for the main thread. */
static void
main (void)
{
GThread *thread1;
GMainContext *thread1_main_context;
/* Spawn a background thread and pass it a reference to its
* GMainContext. Retain a reference for use in this thread
* too. */
thread1_main_context = g_main_context_new ();
g_thread_new ("thread1", thread1_main,
g_main_context_ref (thread1_main_context));
/* Maybe set up your UI here, for example. */
/* Invoke my_func() in the other thread. */
invoke_my_func (thread1_main_context,
"some data which needs passing between threads",
123456, some_object);
/* Continue doing other work. */
}</code>
<p>
This invocation is <em style="strong">uni-directional</em>: it calls
<code>my_func()</code> in <code>thread1</code>, but there’s no way to
return a value to the main thread. To do that, the same principle needs
to be used again, invoking a callback function in the main thread. It’s
a straightforward extension which isn’t covered here.
</p>
<p>
To maintain thread safety, data which is potentially accessed by
multiple threads must make those accesses mutually exclusive using a
<link href="http://en.wikipedia.org/wiki/Mutual_exclusion">mutex</link>.
Data potentially accessed by multiple threads:
<code>thread1_main_context</code>, passed in the fork call to
<code>thread1_main</code>; and <code>some_object</code>, a reference to
which is passed in the data closure. Critically, GLib guarantees that
<code>GMainContext</code> is thread safe, so sharing
<code>thread1_main_context</code> between threads is safe. The example
assumes that other code accessing <code>some_object</code> is thread
safe.
</p>
<p>
Note that <code>some_string</code> and <code>some_int</code> cannot be
accessed from both threads, because <em>copies</em> of them are passed
to <code>thread1</code>, rather than the originals. This is a standard
technique for making cross-thread calls thread safe without requiring
locking. It also avoids the problem of synchronizing freeing
<code>some_string</code>.
</p>
<p>
Similarly, a reference to <code>some_object</code> is transferred to
<code>thread1</code>, which works around the issue of synchronizing
destruction of the object (see <link xref="memory-management"/>).
</p>
<p>
<code>g_idle_source_new()</code> is used rather than the simpler
<code>g_idle_add()</code> so the <code>GMainContext</code> to attach to
can be specified.
</p>
</example>
</section>
<section id="g-main-context-invoke-full">
<title>
Convenience Method: <code>g_main_context_invoke_full()</code>
</title>
<p>
This is simplified greatly by the convenience method,
<link href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-main-context-invoke-full"><code>g_main_context_invoke_full()</code></link>.
It invokes a callback so that the specified <code>GMainContext</code> 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>
<p>
<code>g_main_context_invoke()</code> can be used instead if the user
data does not need to be freed by a <code>GDestroyNotify</code> callback
after the invocation returns.
</p>
<example>
<p>
Modifying the earlier example, the <code>invoke_my_func()</code>
function can be replaced by the following:
</p>
<code mime="text/x-csrc">
static void
invoke_my_func (GMainContext *thread1_main_context,
const gchar *some_string,
guint some_int,
GObject *some_object)
{
MyFuncData *data;
/* Create a data closure to pass all the desired variables
* between threads. */
data = g_new0 (MyFuncData, 1);
data->some_string = g_strdup (some_string);
data->some_int = some_int;
data->some_object = g_object_ref (some_object);
/* Invoke the function. */
g_main_context_invoke_full (thread1_main_context,
G_PRIORITY_DEFAULT, my_func_idle,
data,
(GDestroyNotify) my_func_data_free);
}</code>
<p>
Consider what happens if <code>invoke_my_func()</code> were called
from <code>thread1</code>, rather than from the main thread. With the
original implementation, the idle source would be added to
<code>thread1</code>’s context and dispatched on the context’s next
iteration (assuming no pending dispatches with higher priorities).
With the improved implementation,
<code>g_main_context_invoke_full()</code> will notice that the
specified context is already owned by the thread (or ownership can be
acquired by it), and will call <code>my_func_idle()</code> directly,
rather than attaching a source to the context and delaying the
invocation to the next context iteration.
</p>
<p>
This subtle behavior difference doesn’t matter in most cases, but is
worth bearing in mind since it can affect blocking behavior
(<code>invoke_my_func()</code> would go from taking negligible time,
to taking the same amount of time as <code>my_func()</code> before
returning).
</p>
</example>
</section>
</section>
<section id="checking-threading">
<title>Checking Threading</title>
<p>
It is useful to document which thread each function should be called in,
in the form of an assertion:
</p>
<code mime="text/x-csrc">
g_assert (g_main_context_is_owner (expected_main_context));</code>
<p>
If that’s put at the top of each function, any assertion failure will
highlight a case where a function has been called from the wrong
thread. It is much easier to write these assertions when initially
developing code, rather than debugging race conditions which can easily
result from a function being called in the wrong thread.
</p>
<p>
This technique can also be applied to signal emissions and callbacks,
improving type safety as well as asserting the right context is used. Note
that signal emission via
<link href="https://developer.gnome.org/gobject/stable/gobject-Signals.html#g-signal-emit"><code>g_signal_emit()</code></link>
is synchronous, and doesn’t involve a main context at all.
</p>
<example>
<p>
For example, instead of using the following when emitting a signal:
</p>
<code mime="text/x-csrc" style="invalid">
guint param1; /* arbitrary example parameters */
gchar *param2;
guint retval = 0;
g_signal_emit_by_name (my_object, "some-signal",
param1, param2, &retval);</code>
<p>
The following can be used:
</p>
<code mime="text/x-csrc" style="valid">
static guint
emit_some_signal (GObject *my_object,
guint param1,
const gchar *param2)
{
guint retval = 0;
g_assert (g_main_context_is_owner (expected_main_context));
g_signal_emit_by_name (my_object, "some-signal",
param1, param2, &retval);
return retval;
}</code>
</example>
</section>
<section id="gtask">
<title><code>GTask</code></title>
<p>
<link href="https://developer.gnome.org/gio/stable/GTask.html"><code>GTask</code></link>
provides a slightly different approach to invoking functions in other
threads, which is more suited to the case where a function should be
executed in <em>some</em> background thread, but not a specific one.
</p>
<p>
<code>GTask</code> takes a data closure and a function to execute, and
provides ways to return the result from this function. It handles
everything necessary to run that function in an arbitrary thread belonging
to some thread pool internal to GLib.
</p>
<example>
<p>
By combining
<link xref="#g-main-context-invoke-full"><code>g_main_context_invoke_full()</code></link>
and <code>GTask</code>, it is possible to run a task in a specific context
and effortlessly return its result to the current context:
</p>
<code mime="text/x-csrc">
/* This will be invoked in thread1. */
static gboolean
my_func_idle (gpointer user_data)
{
GTask *task = G_TASK (user_data);
MyFuncData *data;
gboolean retval;
/* Call my_func() and propagate its returned boolean to
* the main thread. */
data = g_task_get_task_data (task);
retval = my_func (data->some_string, data->some_int,
data->some_object);
g_task_return_boolean (task, retval);
return G_SOURCE_REMOVE;
}
/* Whichever thread this is invoked in, the @callback will be
* invoked in, once my_func() has finished and returned a result. */
static void
invoke_my_func_with_result (GMainContext *thread1_main_context,
const gchar *some_string,
guint some_int,
GObject *some_object,
GAsyncReadyCallback callback,
gpointer user_data)
{
MyFuncData *data;
/* Create a data closure to pass all the desired variables
* between threads. */
data = g_new0 (MyFuncData, 1);
data->some_string = g_strdup (some_string);
data->some_int = some_int;
data->some_object = g_object_ref (some_object);
/* Create a GTask to handle returning the result to the current
* thread-default main context. */
task = g_task_new (NULL, NULL, callback, user_data);
g_task_set_task_data (task, data,
(GDestroyNotify) my_func_data_free);
/* Invoke the function. */
g_main_context_invoke_full (thread1_main_context,
G_PRIORITY_DEFAULT, my_func_idle,
task,
(GDestroyNotify) g_object_unref);
}</code>
</example>
</section>
</page>
|