I came came across an unexpected problem with spawn recently and thought I would mention it here in the hope that someone can clarify the situation.
The program below behaves erratically when compiled with --threads:on --gc:arc. Sometimes it runs ok, sometimes it reports 'SIGSEGV: Illegal storage access'. But if I change the code so that the spawned function gets a pointer to the ref object (instead of the ref object) then it runs perfectly.
I assume that arc must be doing some kind of deep copy of the ref object causing my machine to run out of memory (?) but my understanding of arc/threads is that there is no deep copying.
If anyone can explain the situation then it would help me to better use arc and threads.
import threadpool
type
myref = ref object
x: float
type Tmp = ref object
a,b,c,d,e,f,g,h,i,j,k : seq[float]
proc calc( tmp: Tmp ): myref =
result = new(myref)
echo "hello"
let n = 4000
var fv = newseq[FlowVar[myref]](n)
var tmp = new(Tmp)
for i in 0..<n:
fv[i] = spawn calc(tmp)
sync()
echo "ok"
#if the code is changed so that
# proc calc( tmp: Tmp ) --> proc calc( tmp: ptr[Tmp] )
# spawn calc( Tmp ) --> spawn calc( Tmp.unsafeaddr )
# then it runs without errors
Hi Araq
The dev version of nim-1.9.3 (2023-05-08-devel-71f2e1a502ad231e3356217398e2d7fcd6137967) does not seem to offer me the option of --mm:atomicArc (I am using linux_x64) but with --mm:arc it runs the example code without any errors.
I guess nim-1.6.12 that gives the problem has some subtle issues when it runs on my system, but it looks like the problem will be fixed by the next Nim version.
Thanks for your reply, and many thanks for all your work on Nim (I arrived here from Julia and find Nim much easier to use and faster to work with).
FWIW this code crashes about 50% of the time with nim v1.6 + arc
std/threadpool
type
Ans = ref object
x: float
Tmp = ref object
a,b,c,d,e,f,g,h,i,j,k : seq[float]
proc calc( x:Tmp ): Ans =
result = new(Ans)
let n = 48000
var fv = newseq[FlowVar[Ans]](n)
var tmp = new(Tmp)
for i in 0..<n:
fv[i] = spawn calc(tmp)
sync()
but if I change the loop to
for i in 0..<n:
# wrapper function called with tuple of parameters
proc tmpWrapper(x:any): auto =
calc(x[0])
fv[i] = spawn tmpWrapper((tmp,))
then it runs perfectly.
Just thought I should add the info for completeness in case anyone else has similar problems and wants to try this style of workaround.