How to correctly capture variable to be used in proc which fed for a thread?
type MyProc = proc(): void
var threads: array[5, Thread[MyProc]]
proc execThread(prc: MyProc) {.thread.} =
echo "run ok"
prc()
for i in 0..threads.high:
closureScope:
threads[i].createThread execThread, proc () = echo i
threads.joinThread
When above code was ran, the captured i only the last, not each i. Thanks in advance.
By making it as argument for the proc in object seems captured it correctly.
type
MyObpr = object
theproc: proc(x: int): void
thearg: int
var threads: array[5, Thread[MyObpr]]
proc execThread(o: MyObpr) {.thread.} =
echo "run ok"
o.theproc o.thearg
for i in 0..threads.high:
closureScope:
threads[i].createThread execThread, MyObpr(thearg: i,
theproc: proc(x: int) = echo x)
threads.joinThreads
Could anyone explain the different between capturing within body of proc and as argument?
After some thought, the 2nd example didn't capture the i as closure :(
The i was simply used as value for thearg field in MyObpr, theproc only invoked the argument that fed to it.
Is it because of GC-safety so closure cannot capture it?
Is it because of GC-safety so closure cannot capture it?
Yes, variable capturing is prone to races even in languages that have a shared heap GC.
But in general, the capture in Nim captures the variable, not its value, so you need to do something like:
for i in 0..threads.high:
closureScope:
let i = i
captureMe(i)
in general, the capture in Nim captures the variable, not its value
Thanks!
In the example, it's indeed need to declare it first within that scope but I didn't realize it before you mentioned :)
Now it's even able to capture ptr object to change that objects fields value :D
Thinking about it, would be nice if closureScope had an argument to capture the variable. As it stands now, is so redundant:
for i in 0..threads.high:
closureCapture i:
captureMe(i)