nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.6k stars 1.47k forks source link

system.once is not thread safe #8895

Open timotheecour opened 6 years ago

timotheecour commented 6 years ago

system.once isn't thread safe:

template once*(body: untyped): untyped =
  var alreadyExecuted {.global.} = false
  if not alreadyExecuted:
    alreadyExecuted = true
    body

[EDIT] Example

when defined caseSub:
  const N = 10
  var thr: array[N, Thread[int]]
  var count = 0
  proc threadFunc(a: int) {.thread.} =
    once: count.inc
    doAssert count == 1
  proc main =
    for i in 0..<N:
      createThread(thr[i], threadFunc, i)
    joinThreads(thr)
  main()

else:
  import os, strformat
  proc main =
    const nim = getCurrentCompilerExe()
    const exe = "/tmp/z01b"
    const file = currentSourcePath
    # -d:danger
    let cmd = fmt"{nim} c -d:caseSub --threads -o:{exe} {file}"
    echo cmd
    doAssert execShellCmd(cmd) == 0
    for i in 0..<10000:
      let ret = execShellCmd(exe)
      doAssert ret == 0, $i
  main()

Current output

fails after a few iterations: count == 1 [AssertionDefect]

Expected output

works

see also

timotheecour commented 4 years ago

probably needs import rlocks or locks?

EDIT: note from @xflywind : see https://github.com/golang/go/blob/master/src/sync/once.go

timotheecour commented 3 years ago

update: added a minimal repro, see top msg /cc @xflywind