**@wiffel, @Araq:**
Thanks a lot! I really missed that it's impossible to use spawn with closures.
:(
So the sample should look like below one. It's much more verbose, but it works
properly.
import unicode, 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()
type
Container = ref ContainerObj
ContainerObj = object of RootObj
Flk: Lock
FnLen: int
FnCallsTotal: int
FnCallsCur: int
FnCallIndex: int
WorkerThread = Thread[tuple[cont: Container, c: string, value: int]]
proc newContainer(nLen, nCount: int): Container =
result.new()
result.Flk.initLock()
result.FnLen = nLen
result.FnCallsTotal = nLen*nCount
result.FnCallsCur = 0
result.FnCallIndex = 0
proc isTimeToFinish(self: Container): bool =
result = self.FnCallsCur == self.FnCallsTotal
proc isOurCallIndex(self: Container, nCallIndex: int): bool =
result = self.FnCallIndex == nCallIndex
proc goToNextCallIndex(self: Container) =
inc self.FnCallIndex
self.FnCallIndex = self.FnCallIndex mod self.FnLen
inc self.FnCallsCur
proc destroyContainer(cont: var Container) =
cont.Flk.deinitLock()
cont = nil
proc worker(param: tuple[cont: Container, c: string, value: int])
{.thread.} =
while true:
var bWorkDone = true
param.cont.Flk.acquire()
try:
if param.cont.isTimeToFinish:
return
if param.cont.isOurCallIndex(param.value):
param.cont.goToNextCallIndex()
stdout.write param.c
else:
bWorkDone = false
finally:
param.cont.Flk.release()
if not bWorkDone:
sleep(1)
proc multithreadedPrint(sMsg: string, nCount: int) =
var
cont = newContainer(sMsg.len, nCount)
threads: seq[WorkerThread] = newSeq[WorkerThread](sMsg.len)
for i in 0..<sMsg.len:
threads[i].createThread(worker, (cont, sMsg.charAtPosU(i), i))
joinThreads(threads)
destroyContainer(cont)
multithreadedPrint("01234567890123456789", 3)
echo ""