The problem is that threads _go to sleep while still holding a lock_.
Well, the real problem is that afaik there is no guarantee that this code will ever finish, because the scheduler is not required to ever wake the right thread when a bunch of other threads are still waiting. But anyway, Moving the `sleep` call behind the lock seems to work fine in practice: import unicode, threadpool, locks, os proc lenU*(s: string): int = result = s.runeLen proc charAtPosU*(s: string, pos: int): string = assert(pos >= 0 and pos < s.runeLen) result = s.runeAtPos(pos).toUTF8() proc multithreadedPrint(sMsg: string, nCount: int) = var nLen = sMsg.lenU nCallsTotal = 0 nCallsCur = 0 lk: Lock res = 0 proc worker(c: string, value: int) {.gcsafe.}= while true: var found = true acquire(lk) try: if nCallsCur == nCallsTotal: return if res == value: inc res res = res mod nLen inc nCallsCur stdout.write c else: found = false finally: release(lk) if not found: sleep(1) if nLen > 0: if nLen > MaxDistinguishedThread: echo "Your string is too long. Maximum allowed is ", MaxDistinguishedThread, "!" return setMinPoolSize(nLen) setMaxPoolSize(nLen) initLock(lk) try: nCallsTotal = nLen * nCount echo("Total threads: ", nLen) echo("Total calls: ", nCallsTotal) for i in 0..<nLen: spawn worker(sMsg.charAtPosU(i), i) sync() finally: deinitLock(lk) multithreadedPrint("0123456789", 2)