Hello,
I am migrating some multi threaded code to use GTask but I’m getting stuck in my implementation. I have read through the cancellation process of GTask but my understanding is still a little muddy.
Here’s what I’m looking to have happen:
- An GObject is created after the user configures the parameters of its operation from the UI and clicks a button.
- The object creates a GTask during its construction and calls g_task_run_in_thread () to do the operation asynchronously.
- The user can cancel the operation by emitting a signal from the UI’s default main context (via a button), calling g_cancellable_cancel(). If this happens, I am looking to have the GTask return (i.e stop any further operations).
-Once the GTask has been stopped, I want the object to be disposed.
What I have experienced this far using g_task_return_on_cancel () with the flag set to TRUE does exactly what the API description says (return control to calling function and let the task finish out it’s operation), but it’s not what I want. Setting this flag to FALSE triggers the GAsyncReadyCallback but the operations still continue in the background.
I want both the callback to be triggered and the GTask returned on cancel. Does this mean that in each operation would I need to check the cancellable for its cancelled state (something like g_cancellable_is_cancelled)?
Heres a stripped down version of my implementation:
static void
counter_task (GTask *task,
GObject *source_object,
gpointer task_data,
GCancellable *cancellable)
{
MyObject *source = MY_OBJECT (source_object);
TaskData *data = (TaskData *) task_data;
while (data->cycles_remaining > 0)
{
operation_1 (task);
operation_2 (task);
operation_3 (task);
operation_4 (task);
data->cycles_remaining--;
}
}
static void
do_counter_task_async (MyObject *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task = NULL;
TaskData *data = NULL;
data = g_new0 (CounterTaskData, 1);
data->cycles_remaining = self->limit;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_return_on_cancel (task, TRUE);
g_task_set_task_data (task,
data,
(GDestroyNotify) task_data_destroy);
self->measurement_task = task;
g_task_run_in_thread (task, (GTaskThreadFunc) counter_task);
}
static void
counter_task_finish (GObject *source_object,
GAsyncResult *result,
gpointer data)
{
MyObject *source = MY_OBJECT (source_object);
g_signal_emit_by_name (source, "task-end");
g_clear_object (&source->cancellable);
}
// this method is connected to with g_signal_connect on MyObject and invoked from the global default main context
static void
stop_async_task (MyObject *self,
gpointer data)
{
g_cancellable_cancel (self->cancellable);
}
Apologies if I am missing a few simple checks but could someone point me in the right direction to make this possible?
Thanks