@rayman2220 & @mashingan many thanks for your inputs. The locking/signalling
stuff seems a little bit nasty because of the behaviour of the underlying layer
(OS); like always the details hurt
For some usecases (especially you are looping withing the producer/consumer) it
doesn`t matter if a signal is lost (signalling before owning and waiting on the
lock). @mashingan besides of @rayman2220´s comments on your code I think it
could be possible that (under some circumstances) your last signal-call is lost
(n=10) so the chanWaiting thread could possible deadlock.
For my usecase I have a "oneshot"-like behaviour because the thread is calling
signal() only once. So it´s extremely nasty in my eyes that the signal could be
lost. I thought about that and finally I come up with the following solution
now (testcode below). Please correct me if I missed something and the example
is deadlocking on your environment (for me on windows it´s working
@rayman2220:no clue how microsoft has implemented that but it seems that the
signal-call on a condition is acting like a latch i.e. at least one signal-call
is preserved):
import locks,os
# globals
var
thr: Thread[void]
cLock: Lock
lockCond: Cond
rcvWaiting : bool = false
proc threadFunc () {.thread.} =
echo "childthread: starting up"
while true:
# we like to model a one-shot behaviour so ensure that the receiver is
owning the lock
if atomicLoadN[bool](unsafeAddr[bool](rcvWaiting),ATOMIC_SEQ_CST):
signal(lockCond)
echo "childthread: signal sent"
break
sleep(200) # ugly
echo "childthread: terminated"
initLock(cLock)
initCond(lockCond)
createThread(thr, threadFunc)
echo "mainthread:begin"
sleep(3000) # simulate childthread is running before we enter the lock
echo "mainthread: start waiting"
withLock(cLock):
# signal the sender that we are owning the lock now
atomicStoreN[bool](unsafeAddr[bool](rcvWaiting),true,ATOMIC_SEQ_CST)
wait(lockCond,cLock)
echo "mainthread: end waiting, sig received"
joinThreads(thr)
deinitLock(cLock)
deinitCond(lockCond)
echo "mainthread:end"