Dear all,
I'm an excited, but rather new user of Nim and recently tried using threadpool to process data (read from a file line by line) in parallel with spawn. Weirdly enough the code failed during runtime with
gc.nim(198) nimGCref
gc.nim(191) incRef
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
I constructed a minimal working example that shows it fails only, if the worker returns an empty string (which in my case is valid).
import threadpool
#{.experimental: "parallel".}
proc doStuff(plp: string): string {.noSideEffect.} =
#return "works"
return ""# doesn't work
proc call*(fName: string, maxThreads = 1) =
var fh: File = if fName == "-": stdin else: open(fName)
defer:
if fh != stdin:
fh.close
setMaxPoolSize(maxThreads)
for line in fh.lines:
discard spawn doStuff(line)
when isMainModule:
import cligen
dispatch(call)
This is obviously utterly artificial now and doesn't do anything at all, but if it's enough to trigger the GC SIGSEV. As soon as you return anything but an empty string, the example works just fine.
Could anyone give me some pointers as to what's going on?
Thanks a lot, Andreas
PS: I'm using Nim Compiler Version 0.19.0 [MacOSX: amd64]
GC is thread-local.
If you allocate a sequence or string or reference type in another thread you will segfault.
For temporaries you can use setupForeignThreadGC() and teardownForeignThreadGc().
If you need to merge partial results of GC-ed types I'm not sure but this thread might help: https://forum.nim-lang.org/t/959