-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
closes #8895 add std/once #16192
closes #8895 add std/once #16192
Conversation
lib/std/once.nim
Outdated
@@ -0,0 +1,31 @@ | |||
import atomics | |||
import locks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about re-entrant code? do we need a ronce / reentrantOnce
(rlocks), or can once
be made re-entrant safe without overhead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of implementing a new module for this, can't we fix system.once
instead?
tests/stdlib/tonce.nim
Outdated
for i in 1 .. 10: | ||
once(block1): | ||
inc count | ||
for i in 0..high(thr): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more idiomatic:
for t in mitems(thr):
createThread(t, threadFunc)
(and Example code in
Line 41 in 73299b0
## for i in 0..high(thr): |
ditto below
if it can be done transparently for user code and it doesn't add new dependencies to system.nim, yes, but with the way it's done in this PR at least, this isn't the case as it requires an extra parameter
|
tests/stdlib/tonce.nim
Outdated
for i in 0..high(thr): | ||
createThread(thr[i], threadFunc) | ||
joinThreads(thr) | ||
doAssert count == 5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else: static doAssert false
(prevents silent misuse)
tests/stdlib/tonce.nim
Outdated
|
||
when defined(caseA): | ||
block: | ||
var thr: array[0..4, Thread[void]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more idiomatic:
var thr: array[5, Thread[void]]
- and as https://github.com/nim-lang/Nim/pull/16192/files#r540547170 upstream code in threads.nim should be updated
tests/stdlib/tonce.nim
Outdated
for i in 0..high(thr): | ||
createThread(thr[i], threadFunc) | ||
joinThreads(thr) | ||
doAssert count == 5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doAssert count == thr.len
tests/stdlib/tonce.nim
Outdated
@@ -0,0 +1,34 @@ | |||
discard """ | |||
cmd: "nim c -r --threads:on $options $file" | |||
matrix: "-d:caseA; -d:caseB" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here you actually don't need matrix for that since you can combine both:
block:
var thr: array[0..4, Thread[void]]
...
block:
var thr: array[0..4, Thread[void]]
...
but instead, use matrix for:
matrix: "--threads:off; --threads:on"
and adjust code to work with and without threads with compileOption
. There are ways to do it without any code duplication.
@@ -0,0 +1,34 @@ | |||
discard """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
js needs to be supported because system.once
already works in js (not considering edge case of webworkers)
(and leave a TODO for supporting VM because VM already doesn't work with system.once)
when true:
var count = 0
var countCT {.compileTime.} = 0
proc fn(n: int) =
once:
when nimvm:
countCT.inc
else:
count.inc
echo (n,)
if n > 1:
fn(n-1)
proc main() =
fn(5)
fn(4)
when nimvm:
echo countCT
# doAssert countCT == 1 # fails
else:
doAssert count == 1
static: main()
main()
tests/stdlib/tonce.nim
Outdated
initOnce(block1) | ||
for i in 1 .. 10: | ||
once(block1): | ||
inc count |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we also need a test where the code in once block raises
lib/std/once.nim
Outdated
try: | ||
body | ||
finally: | ||
cond.finished.store(true, moRelease) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering whether we should customize whether cond.finished.store(true, moRelease)
happens in a finally
block or only after a successful body
that didn't raise.
there are use cases for both.
eg:
var db: MyDataBase
proc fn=
once(Once, retryOnFailure = true):
db = newMyDataBaseFlaky() # suppose this fails 10% of the times
# we want to make sure `db` is always initialized here
db.call() # if `newMyDataBase` raised in another thread, `db` will be nil
without retryOnFailure
flag, how would you emulate retryOnFailure
in user code calling std/once
?
Should be named |
lib/std/once.nim
Outdated
finished: Atomic[bool] | ||
lock: Lock | ||
|
||
proc initOnce*(once: var Once) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be func
?.
|
What word is |
fix #8895
add thread-safe once to std/once, for ORC.