docs: Move the GTask SECTION

Move it to the struct docs.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3037
This commit is contained in:
Philip Withnall 2023-11-14 15:12:21 +00:00
parent 3d8f1dc203
commit de56743bf6

View File

@ -33,43 +33,39 @@
#include <string.h> #include <string.h>
/** /**
* SECTION:gtask * GTask:
* @short_description: Cancellable synchronous or asynchronous task
* and result
* @include: gio/gio.h
* @see_also: #GAsyncResult
* *
* A #GTask represents and manages a cancellable "task". * A `GTask` represents and manages a cancellable task.
* *
* ## Asynchronous operations * ## Asynchronous operations
* *
* The most common usage of #GTask is as a #GAsyncResult, to * The most common usage of `GTask` is as a [iface@Gio.AsyncResult], to
* manage data during an asynchronous operation. You call * manage data during an asynchronous operation. You call
* g_task_new() in the "start" method, followed by * [ctor@Gio.Task.new] in the start method, followed by
* g_task_set_task_data() and the like if you need to keep some * [method@Gio.Task.set_task_data] and the like if you need to keep some
* additional data associated with the task, and then pass the * additional data associated with the task, and then pass the
* task object around through your asynchronous operation. * task object around through your asynchronous operation.
* Eventually, you will call a method such as * Eventually, you will call a method such as
* g_task_return_pointer() or g_task_return_error(), which will * [method@Gio.Task.return_pointer] or [method@Gio.Task.return_error], which
* save the value you give it and then invoke the task's callback * will save the value you give it and then invoke the tasks callback
* function in the * function in the thread-default main context (see
* [thread-default main context][g-main-context-push-thread-default] * [method@GLib.MainContext.push_thread_default])
* where it was created (waiting until the next iteration of the main * where it was created (waiting until the next iteration of the main
* loop first, if necessary). The caller will pass the #GTask back to * loop first, if necessary). The caller will pass the `GTask` back to
* the operation's finish function (as a #GAsyncResult), and you can * the operations finish function (as a [iface@Gio.AsyncResult]), and you can
* use g_task_propagate_pointer() or the like to extract the * use [method@Gio.Task.propagate_pointer] or the like to extract the
* return value. * return value.
* *
* Using #GTask requires the thread-default #GMainContext from when the * Using `GTask` requires the thread-default [struct@GLib.MainContext] from when
* #GTask was constructed to be running at least until the task has completed * the `GTask` was constructed to be running at least until the task has
* and its data has been freed. * completed and its data has been freed.
* *
* If a #GTask has been constructed and its callback set, it is an error to * If a `GTask` has been constructed and its callback set, it is an error to
* not call `g_task_return_*()` on it. GLib will warn at runtime if this happens * not call `g_task_return_*()` on it. GLib will warn at runtime if this happens
* (since 2.76). * (since 2.76).
* *
* Here is an example for using GTask as a GAsyncResult: * Here is an example for using `GTask` as a [iface@Gio.AsyncResult]:
* |[<!-- language="C" --> * ```c
* typedef struct { * typedef struct {
* CakeFrostingType frosting; * CakeFrostingType frosting;
* char *message; * char *message;
@ -161,22 +157,23 @@
* *
* return g_task_propagate_pointer (G_TASK (result), error); * return g_task_propagate_pointer (G_TASK (result), error);
* } * }
* ]| * ```
* *
* ## Chained asynchronous operations * ## Chained asynchronous operations
* *
* #GTask also tries to simplify asynchronous operations that * `GTask` also tries to simplify asynchronous operations that
* internally chain together several smaller asynchronous * internally chain together several smaller asynchronous
* operations. g_task_get_cancellable(), g_task_get_context(), * operations. [method@Gio.Task.get_cancellable], [method@Gio.Task.get_context],
* and g_task_get_priority() allow you to get back the task's * and [method@Gio.Task.get_priority] allow you to get back the tasks
* #GCancellable, #GMainContext, and [I/O priority][io-priority] * [class@Gio.Cancellable], [struct@GLib.MainContext], and
* when starting a new subtask, so you don't have to keep track * [I/O priority](iface.AsyncResult.html#io-priority)
* of them yourself. g_task_attach_source() simplifies the case * when starting a new subtask, so you dont have to keep track
* of them yourself. [method@Gio.Task.attach_source] simplifies the case
* of waiting for a source to fire (automatically using the correct * of waiting for a source to fire (automatically using the correct
* #GMainContext and priority). * [struct@GLib.MainContext] and priority).
* *
* Here is an example for chained asynchronous operations: * Here is an example for chained asynchronous operations:
* |[<!-- language="C" --> * ```c
* typedef struct { * typedef struct {
* Cake *cake; * Cake *cake;
* CakeFrostingType frosting; * CakeFrostingType frosting;
@ -259,7 +256,7 @@
* GSource *source; * GSource *source;
* *
* source = cake_decorator_wait_source_new (cake); * source = cake_decorator_wait_source_new (cake);
* // Attach @source to @task's GMainContext and have it call * // Attach @source to @tasks GMainContext and have it call
* // decorator_ready() when it is ready. * // decorator_ready() when it is ready.
* g_task_attach_source (task, source, decorator_ready); * g_task_attach_source (task, source, decorator_ready);
* g_source_unref (source); * g_source_unref (source);
@ -300,18 +297,18 @@
* *
* return g_task_propagate_pointer (G_TASK (result), error); * return g_task_propagate_pointer (G_TASK (result), error);
* } * }
* ]| * ```
* *
* ## Asynchronous operations from synchronous ones * ## Asynchronous operations from synchronous ones
* *
* You can use g_task_run_in_thread() to turn a synchronous * You can use [method@Gio.Task.run_in_thread] to turn a synchronous
* operation into an asynchronous one, by running it in a thread. * operation into an asynchronous one, by running it in a thread.
* When it completes, the result will be dispatched to the * When it completes, the result will be dispatched to the thread-default main
* [thread-default main context][g-main-context-push-thread-default] * context (see [method@GLib.MainContext.push_thread_default]) where the `GTask`
* where the #GTask was created. * was created.
* *
* Running a task in a thread: * Running a task in a thread:
* |[<!-- language="C" --> * ```c
* typedef struct { * typedef struct {
* guint radius; * guint radius;
* CakeFlavor flavor; * CakeFlavor flavor;
@ -379,24 +376,24 @@
* *
* return g_task_propagate_pointer (G_TASK (result), error); * return g_task_propagate_pointer (G_TASK (result), error);
* } * }
* ]| * ```
* *
* ## Adding cancellability to uncancellable tasks * ## Adding cancellability to uncancellable tasks
* *
* Finally, g_task_run_in_thread() and g_task_run_in_thread_sync() * Finally, [method@Gio.Task.run_in_thread] and
* can be used to turn an uncancellable operation into a * [method@Gio.Task.run_in_thread_sync] can be used to turn an uncancellable
* cancellable one. If you call g_task_set_return_on_cancel(), * operation into a cancellable one. If you call
* passing %TRUE, then if the task's #GCancellable is cancelled, * [method@Gio.Task.set_return_on_cancel], passing `TRUE`, then if the tasks
* it will return control back to the caller immediately, while * [class@Gio.Cancellable] is cancelled, it will return control back to the
* allowing the task thread to continue running in the background * caller immediately, while allowing the task thread to continue running in the
* (and simply discarding its result when it finally does finish). * background (and simply discarding its result when it finally does finish).
* Provided that the task thread is careful about how it uses * Provided that the task thread is careful about how it uses
* locks and other externally-visible resources, this allows you * locks and other externally-visible resources, this allows you
* to make "GLib-friendly" asynchronous and cancellable * to make GLib-friendly asynchronous and cancellable
* synchronous variants of blocking APIs. * synchronous variants of blocking APIs.
* *
* Cancelling a task: * Cancelling a task:
* |[<!-- language="C" --> * ```c
* static void * static void
* bake_cake_thread (GTask *task, * bake_cake_thread (GTask *task,
* gpointer source_object, * gpointer source_object,
@ -417,8 +414,8 @@
* return; * return;
* } * }
* *
* // If the task has already been cancelled, then we don't want to add * // If the task has already been cancelled, then we dont want to add
* // the cake to the cake cache. Likewise, we don't want to have the * // the cake to the cake cache. Likewise, we dont want to have the
* // task get cancelled in the middle of updating the cache. * // task get cancelled in the middle of updating the cache.
* // g_task_set_return_on_cancel() will return %TRUE here if it managed * // g_task_set_return_on_cancel() will return %TRUE here if it managed
* // to disable return-on-cancel, or %FALSE if the task was cancelled * // to disable return-on-cancel, or %FALSE if the task was cancelled
@ -426,11 +423,11 @@
* if (g_task_set_return_on_cancel (task, FALSE)) * if (g_task_set_return_on_cancel (task, FALSE))
* { * {
* // If the caller cancels at this point, their * // If the caller cancels at this point, their
* // GAsyncReadyCallback won't be invoked until we return, * // GAsyncReadyCallback wont be invoked until we return,
* // so we don't have to worry that this code will run at * // so we dont have to worry that this code will run at
* // the same time as that code does. But if there were * // the same time as that code does. But if there were
* // other functions that might look at the cake cache, * // other functions that might look at the cake cache,
* // then we'd probably need a GMutex here as well. * // then wed probably need a GMutex here as well.
* baker_add_cake_to_cache (baker, cake); * baker_add_cake_to_cache (baker, cake);
* g_task_return_pointer (task, cake, g_object_unref); * g_task_return_pointer (task, cake, g_object_unref);
* } * }
@ -485,68 +482,69 @@
* g_object_unref (task); * g_object_unref (task);
* return cake; * return cake;
* } * }
* ]| * ```
* *
* ## Porting from GSimpleAsyncResult * ## Porting from [class@Gio.SimpleAsyncResult]
* *
* #GTask's API attempts to be simpler than #GSimpleAsyncResult's * `GTask`s API attempts to be simpler than [class@Gio.SimpleAsyncResult]s
* in several ways: * in several ways:
* - You can save task-specific data with g_task_set_task_data(), and *
* retrieve it later with g_task_get_task_data(). This replaces the * - You can save task-specific data with [method@Gio.Task.set_task_data], and
* abuse of g_simple_async_result_set_op_res_gpointer() for the same * retrieve it later with [method@Gio.Task.get_task_data]. This replaces the
* purpose with #GSimpleAsyncResult. * abuse of [method@Gio.SimpleAsyncResult.set_op_res_gpointer] for the same
* - In addition to the task data, #GTask also keeps track of the * purpose with [class@Gio.SimpleAsyncResult].
* [priority][io-priority], #GCancellable, and * - In addition to the task data, `GTask` also keeps track of the
* #GMainContext associated with the task, so tasks that consist of * [priority](iface.AsyncResult.html#io-priority), [class@Gio.Cancellable],
* a chain of simpler asynchronous operations will have easy access * and [struct@GLib.MainContext] associated with the task, so tasks that
* consist of a chain of simpler asynchronous operations will have easy access
* to those values when starting each sub-task. * to those values when starting each sub-task.
* - g_task_return_error_if_cancelled() provides simplified * - [method@Gio.Task.return_error_if_cancelled] provides simplified
* handling for cancellation. In addition, cancellation * handling for cancellation. In addition, cancellation
* overrides any other #GTask return value by default, like * overrides any other `GTask` return value by default, like
* #GSimpleAsyncResult does when * [class@Gio.SimpleAsyncResult] does when
* g_simple_async_result_set_check_cancellable() is called. * [method@Gio.SimpleAsyncResult.set_check_cancellable] is called.
* (You can use g_task_set_check_cancellable() to turn off that * (You can use [method@Gio.Task.set_check_cancellable] to turn off that
* behavior.) On the other hand, g_task_run_in_thread() * behavior.) On the other hand, [method@Gio.Task.run_in_thread]
* guarantees that it will always run your * guarantees that it will always run your
* `task_func`, even if the task's #GCancellable * `task_func`, even if the tasks [class@Gio.Cancellable]
* is already cancelled before the task gets a chance to run; * is already cancelled before the task gets a chance to run;
* you can start your `task_func` with a * you can start your `task_func` with a
* g_task_return_error_if_cancelled() check if you need the * [method@Gio.Task.return_error_if_cancelled] check if you need the
* old behavior. * old behavior.
* - The "return" methods (eg, g_task_return_pointer()) * - The return methods (eg, [method@Gio.Task.return_pointer])
* automatically cause the task to be "completed" as well, and * automatically cause the task to be completed as well, and
* there is no need to worry about the "complete" vs "complete * there is no need to worry about the complete vs complete in idle
* in idle" distinction. (#GTask automatically figures out * distinction. (`GTask` automatically figures out
* whether the task's callback can be invoked directly, or * whether the tasks callback can be invoked directly, or
* if it needs to be sent to another #GMainContext, or delayed * if it needs to be sent to another [struct@GLib.MainContext], or delayed
* until the next iteration of the current #GMainContext.) * until the next iteration of the current [struct@GLib.MainContext].)
* - The "finish" functions for #GTask based operations are generally * - The finish functions for `GTask` based operations are generally
* much simpler than #GSimpleAsyncResult ones, normally consisting * much simpler than [class@Gio.SimpleAsyncResult] ones, normally consisting
* of only a single call to g_task_propagate_pointer() or the like. * of only a single call to [method@Gio.Task.propagate_pointer] or the like.
* Since g_task_propagate_pointer() "steals" the return value from * Since [method@Gio.Task.propagate_pointer] steals the return value from
* the #GTask, it is not necessary to juggle pointers around to * the `GTask`, it is not necessary to juggle pointers around to
* prevent it from being freed twice. * prevent it from being freed twice.
* - With #GSimpleAsyncResult, it was common to call * - With [class@Gio.SimpleAsyncResult], it was common to call
* g_simple_async_result_propagate_error() from the * [method@Gio.SimpleAsyncResult.propagate_error] from the
* `_finish()` wrapper function, and have * `_finish()` wrapper function, and have
* virtual method implementations only deal with successful * virtual method implementations only deal with successful
* returns. This behavior is deprecated, because it makes it * returns. This behavior is deprecated, because it makes it
* difficult for a subclass to chain to a parent class's async * difficult for a subclass to chain to a parent classs async
* methods. Instead, the wrapper function should just be a * methods. Instead, the wrapper function should just be a
* simple wrapper, and the virtual method should call an * simple wrapper, and the virtual method should call an
* appropriate `g_task_propagate_` function. * appropriate `g_task_propagate_` function.
* Note that wrapper methods can now use * Note that wrapper methods can now use
* g_async_result_legacy_propagate_error() to do old-style * [method@Gio.AsyncResult.legacy_propagate_error] to do old-style
* #GSimpleAsyncResult error-returning behavior, and * [class@Gio.SimpleAsyncResult] error-returning behavior, and
* g_async_result_is_tagged() to check if a result is tagged as * [method@Gio.AsyncResult.is_tagged] to check if a result is tagged as
* having come from the `_async()` wrapper * having come from the `_async()` wrapper
* function (for "short-circuit" results, such as when passing * function (for short-circuit results, such as when passing
* 0 to g_input_stream_read_async()). * `0` to [method@Gio.InputStream.read_async]).
* *
* ## Thread-safety considerations * ## Thread-safety considerations
* *
* Due to some infelicities in the API design, there is a * Due to some infelicities in the API design, there is a
* thread-safety concern that users of GTask have to be aware of: * thread-safety concern that users of `GTask` have to be aware of:
* *
* If the `main` thread drops its last reference to the source object * If the `main` thread drops its last reference to the source object
* or the task data before the task is finalized, then the finalizers * or the task data before the task is finalized, then the finalizers
@ -556,19 +554,11 @@
* can lead to hard-to-debug crashes. Possible workarounds include: * can lead to hard-to-debug crashes. Possible workarounds include:
* *
* - Clear task data in a signal handler for `notify::completed` * - Clear task data in a signal handler for `notify::completed`
*
* - Keep iterating a main context in the main thread and defer * - Keep iterating a main context in the main thread and defer
* dropping the reference to the source object to that main * dropping the reference to the source object to that main
* context when the task is finalized * context when the task is finalized
*/ */
/**
* GTask:
*
* The opaque object representing a synchronous or asynchronous task
* and its result.
*/
struct _GTask { struct _GTask {
GObject parent_instance; GObject parent_instance;
@ -962,7 +952,7 @@ g_task_set_task_data (GTask *task,
/** /**
* g_task_set_priority: * g_task_set_priority:
* @task: the #GTask * @task: the #GTask
* @priority: the [priority][io-priority] of the request * @priority: the [priority](iface.AsyncResult.html#io-priority) of the request
* *
* Sets @task's priority. If you do not call this, it will default to * Sets @task's priority. If you do not call this, it will default to
* %G_PRIORITY_DEFAULT. * %G_PRIORITY_DEFAULT.
@ -1787,8 +1777,9 @@ g_task_run_in_thread_sync (GTask *task,
* *
* A utility function for dealing with async operations where you need * A utility function for dealing with async operations where you need
* to wait for a #GSource to trigger. Attaches @source to @task's * to wait for a #GSource to trigger. Attaches @source to @task's
* #GMainContext with @task's [priority][io-priority], and sets @source's * #GMainContext with @task's [priority](iface.AsyncResult.html#io-priority),
* callback to @callback, with @task as the callback's `user_data`. * and sets @source's callback to @callback, with @task as the callback's
* `user_data`.
* *
* It will set the @sources name to the tasks name (as set with * It will set the @sources name to the tasks name (as set with
* g_task_set_name()), if one has been set on the task and the source doesnt * g_task_set_name()), if one has been set on the task and the source doesnt