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