Threads

While the cooperative async model offers an efficient model for dealing with many tasks that often are blocked on I/O, it is not suitable for long-running computations that would prevent concurrent tasks from progressing.

Multithreading offers a way to offload heavy computations to be executed in parallel with the async work, or, in cases where a single event loop gets overloaded, to manage multiple event loops in parallel.

For interaction between threads, the ThreadSignalPtr type (found in the (chronos/threadsync)(https://github.com/status-im/nim-chronos/blob/master/chronos/threadsync.nim) module) is used - both to wait for notifications coming from other threads and to notify other threads of progress from within an async procedure.

import chronos, chronos/threadsync
import os

type
  Context = object
    # Context allocated by `createShared` should contain no garbage-collected
    # types!
    signal: ThreadSignalPtr
    value: int

proc myThread(ctx: ptr Context) {.thread.} =
  echo "Doing some work in a thread"
  sleep(3000)
  ctx.value = 42
  echo "Done, firing the signal"
  discard ctx.signal.fireSync().expect("correctly initialized signal should not fail")

proc main() {.async.} =
  let
    signal = ThreadSignalPtr.new().expect("free file descriptor for signal")
    context = createShared(Context)
  context.signal = signal

  var thread: Thread[ptr Context]

  echo "Starting thread"
  createThread(thread, myThread, context)

  await signal.wait()

  echo "Work done: ", context.value

  joinThread(thread)

  signal.close().expect("closing once works")
  deallocShared(context)

waitFor main()