# The TaskRunner

The task runner runs long-running operations on a puzzle. It is used
to run operations that take more than a frame to complete, and uses a
thread to do so. Currently, there are four tasks that use it: The
**[Word Solver](word-solver.md)**, the **Anagram Solver**, the **Theme
Word Fitter**, and the **[Grid Fill Task](ac3.md)**.

## API and State

All tasks must inherit from `PuzzleTask`, and implement the `run` and
`set_run_info` class methods.

 * `task_runner_run()`: Transitions to RUNNING. Initializes a new
 TaskContext. If a previous COMPLETE task existed, it is reset first.
 * `task_runner_cancel()`: Cancels the task. The task enters the
   COMPLETE state upon yielding. Results collected up to the
   cancellation point remain accessible via
   `task_runner_get_result()`.
 * `task_runner_reset()`: Immediately transitions the runner to
   READY. If a thread is active, it is cancelled and marked for
   background cleanup; its results become inaccessible immediately.

## Progress Updates

Tasks can provide intermediate results while they are running. There
are two ways of doing this that are thread safe:

1. There's a `count` gint that can be used to indicate number of
   runs. It can be updated with `g_atomic_int_inc ()`
2. There's a results array (with associated `GMutex`) that results (a
   `gpointer`) can be placed in. Either unique results can be put
   there, or a single item that's updated. In the case of the latter,
   care should be taken to lock it.

In the main thread, the UI can poll the task for updates in a
timeout. In addition, there's a thread-safe `TaskRunner::updated`
signal that can be triggered within the job by calling
`puzzle_task_update()`. This can let the main thread know to check the
`results` array for updates.

When the task is done `TaskRunner::finished` is emitted.
