Look at the following code:
## nim c --mm:refc a.nim
type
Foo = ref object
a: int
proc unsafe_ref_count(x: ref): int =
let p = cast[ptr UncheckedArray[int]](x)
p[-2] shr 3
proc main(px: ptr Foo) =
let x = px[]
proc p1() =
inc x.a
echo "ref in ", x.unsafe_ref_count
p1()
echo "ref out ", x.unsafe_ref_count
when isMainModule:
var x = Foo(a: 5)
for _ in 1..5:
main(x.addr)
echo "ref last ", x.unsafe_ref_count
compile the code with --mm:refc and give the following output:
ref in 2
ref out 2
ref in 3
ref out 3
ref in 4
ref out 4
ref in 5
ref out 5
ref in 6
ref out 6
ref last 6
If I change the closure proc p1() to template p1(), then the output is:
ref in 1
ref out 1
ref in 1
ref out 1
ref in 1
ref out 1
ref in 1
ref out 1
ref in 1
ref out 1
ref last 1
These is the expected behaviour.
Thank you, that make sence. :)
I have a real world bug related this, it is troubled me for long time, please give me some hints if possible.
The real world program like this:
I have an big ref object named as BigObj, which I pass to several children thread with pointer, because I don't want it is to be copied. The BigObj is readonly both in main thread and children thread, and main thread will wait till all children thread finish there job. Now the problem comes, in the child thread, If I use closure to access the BigObj, after some iteration, the BigObj is freeed(The inner data changed so I think the only possible reason is it be freeed); if I use template, the program works fine. If I use the closure and add an GC_Ref(BigObj) call, the program works fine too.
So, what is possible reason for this?
You are very correct. I change the incRef/decRef to atomicInc/atomicDec in gc.nim, then the program work fine. :)
Thank you.