I'm hoping someone can shed light on why this program occasionally fails to terminate. I compiled it with Nim 0.18.0 on Linux x64, GCC 5.4.0.
During most executions, the worker threads receive their terminal message, and exit. But sometimes they don't get the message, so they are stuck in recv() indefinitely. What conditions could cause a message sent from the main thread to not be received by a worker?
# nim c --threads:on test.nim && while true; do ./test; done
import strformat
type
  InMsg = object
    payload: int
  
  InChan = Channel[InMsg]
  
  WorkerArg = object
    id: int
    chanp: ptr InChan
  
  Worker = Thread[WorkerArg]
proc worker(arg: WorkerArg) {.thread.} =
  var chan = arg.chanp[]
  while true:
    var msg : InMsg = recv(chan)
    if msg.payload == 0:        # the kill signal
        break
  echo fmt"{arg.id}: worker done."
proc main() =
  const N = 5
  var
    chans: array[1..N, InChan]
    workers : array[1..N, Worker]
    msg: InMsg
  for i in 1..N:
    chans[i].open
    let
      arg = WorkerArg(id:i, chanp:addr chans[i])
    createThread(workers[i], worker, arg)
    msg.payload = 0             # send the kill signal
    send(chans[i], msg)
  joinThreads(workers)
  echo "program complete."
if isMainModule:
  main()
You can't copy a channel, what you're essentially doing in var chan = arg.chanp[]. Instead you can keep its address: let chanp = arg.chanp, and dereference it on recv: var msg : InMsg = recv(chanp[]).
This is happening because Channel has mutexes, and posix mutexes don't like to be copied in memory.
Ah, thank you yglukhov, that makes sense!
Best, Graham