fixes #71; sorry about the polling implementation
This commit is contained in:
parent
24e1d22ec9
commit
c6213c9774
6 changed files with 62 additions and 12 deletions
|
|
@ -720,7 +720,8 @@ proc generateHeader(p: var TProc, typ: PType): PRope =
|
||||||
const
|
const
|
||||||
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||||
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString,
|
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString,
|
||||||
nkCStringToString, nkCall, nkCommand, nkHiddenCallConv, nkCallStrLit}
|
nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
|
||||||
|
nkCommand, nkHiddenCallConv, nkCallStrLit}
|
||||||
|
|
||||||
proc needsNoCopy(y: PNode): bool =
|
proc needsNoCopy(y: PNode): bool =
|
||||||
result = (y.kind in nodeKindsNeedNoCopy) or
|
result = (y.kind in nodeKindsNeedNoCopy) or
|
||||||
|
|
@ -1402,7 +1403,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
|
||||||
else: r.res = toRope(f.ToStrMaxPrecision)
|
else: r.res = toRope(f.ToStrMaxPrecision)
|
||||||
of nkBlockExpr: genBlock(p, n, r)
|
of nkBlockExpr: genBlock(p, n, r)
|
||||||
of nkIfExpr: genIfExpr(p, n, r)
|
of nkIfExpr: genIfExpr(p, n, r)
|
||||||
of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit:
|
of nkCallKinds:
|
||||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
|
||||||
genMagic(p, n, r)
|
genMagic(p, n, r)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
## a channel as its inbox. This module requires the ``--threads:on``
|
## a channel as its inbox. This module requires the ``--threads:on``
|
||||||
## command line switch.
|
## command line switch.
|
||||||
|
|
||||||
|
from os import sleep
|
||||||
|
|
||||||
type
|
type
|
||||||
TTask*[TIn, TOut] = object{.pure, final.}
|
TTask*[TIn, TOut] = object{.pure, final.}
|
||||||
when TOut isnot void:
|
when TOut isnot void:
|
||||||
|
|
@ -29,7 +31,7 @@ type
|
||||||
proc spawn*[TIn, TOut](action: proc(
|
proc spawn*[TIn, TOut](action: proc(
|
||||||
self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
|
self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
|
||||||
## creates an actor; that is a thread with an inbox. The caller MUST call
|
## creates an actor; that is a thread with an inbox. The caller MUST call
|
||||||
## ``join`` because that also frees the associated resources with the actor.
|
## ``join`` because that also frees the actor's associated resources.
|
||||||
result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
|
result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
|
||||||
open(result.i)
|
open(result.i)
|
||||||
createThread(result.t, action, result)
|
createThread(result.t, action, result)
|
||||||
|
|
@ -42,6 +44,10 @@ proc running*[TIn, TOut](a: PActor[TIn, TOut]) =
|
||||||
## returns true if the actor `a` is running.
|
## returns true if the actor `a` is running.
|
||||||
result = running(a.t)
|
result = running(a.t)
|
||||||
|
|
||||||
|
proc ready*[TIn, TOut](a: PActor[TIn, TOut]): bool =
|
||||||
|
## returns true if the actor `a` is ready to process new messages.
|
||||||
|
result = ready(a.i)
|
||||||
|
|
||||||
proc join*[TIn, TOut](a: PActor[TIn, TOut]) =
|
proc join*[TIn, TOut](a: PActor[TIn, TOut]) =
|
||||||
## joins an actor.
|
## joins an actor.
|
||||||
joinThread(a.t)
|
joinThread(a.t)
|
||||||
|
|
@ -111,17 +117,35 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
|
||||||
for i in 0 .. < a.actors.len:
|
for i in 0 .. < a.actors.len:
|
||||||
a.actors[i] = spawn(poolWorker[TIn, TOut])
|
a.actors[i] = spawn(poolWorker[TIn, TOut])
|
||||||
|
|
||||||
proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
|
proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
|
||||||
## waits for each actor in the actor pool `a` to finish and frees the
|
## waits for every actor of `a` to finish with its work. Currently this is
|
||||||
|
## implemented as polling every `polling` ms. This will change in a later
|
||||||
|
## version, however.
|
||||||
|
while true:
|
||||||
|
var wait = false
|
||||||
|
for i in 0..high(a.actors):
|
||||||
|
if not a.actors[i].i.ready:
|
||||||
|
wait = true
|
||||||
|
break
|
||||||
|
if not wait: break
|
||||||
|
sleep(polling)
|
||||||
|
|
||||||
|
proc terminate*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
|
||||||
|
## terminates each actor in the actor pool `a` and frees the
|
||||||
## resources attached to `a`.
|
## resources attached to `a`.
|
||||||
var t: TTask[TIn, TOut]
|
var t: TTask[TIn, TOut]
|
||||||
t.shutdown = true
|
t.shutdown = true
|
||||||
for i in 0 .. < a.actors.len: send(a.actors[i].i, t)
|
for i in 0.. <a.actors.len: send(a.actors[i].i, t)
|
||||||
for i in 0 .. < a.actors.len: join(a.actors[i])
|
for i in 0.. <a.actors.len: join(a.actors[i])
|
||||||
when TOut isnot void:
|
when TOut isnot void:
|
||||||
close(a.outputs)
|
close(a.outputs)
|
||||||
a.actors = nil
|
a.actors = nil
|
||||||
|
|
||||||
|
proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
|
||||||
|
## short-cut for `sync` and then `terminate`.
|
||||||
|
sync(a)
|
||||||
|
terminate(a)
|
||||||
|
|
||||||
template setupTask =
|
template setupTask =
|
||||||
t.action = action
|
t.action = action
|
||||||
shallowCopy(t.data, input)
|
shallowCopy(t.data, input)
|
||||||
|
|
@ -135,7 +159,7 @@ template schedule =
|
||||||
return
|
return
|
||||||
# no thread ready :-( --> send message to the thread which has the least
|
# no thread ready :-( --> send message to the thread which has the least
|
||||||
# messages pending:
|
# messages pending:
|
||||||
var minIdx = 0
|
var minIdx = -1
|
||||||
var minVal = high(int)
|
var minVal = high(int)
|
||||||
for i in 0..high(p.actors):
|
for i in 0..high(p.actors):
|
||||||
var curr = p.actors[i].i.peek
|
var curr = p.actors[i].i.peek
|
||||||
|
|
@ -143,10 +167,13 @@ template schedule =
|
||||||
# ok, is ready now:
|
# ok, is ready now:
|
||||||
p.actors[i].i.send(t)
|
p.actors[i].i.send(t)
|
||||||
return
|
return
|
||||||
if curr < minVal:
|
if curr < minVal and curr >= 0:
|
||||||
minVal = curr
|
minVal = curr
|
||||||
minIdx = i
|
minIdx = i
|
||||||
p.actors[minIdx].i.send(t)
|
if minIdx >= 0:
|
||||||
|
p.actors[minIdx].i.send(t)
|
||||||
|
else:
|
||||||
|
raise newException(EDeadThread, "cannot send message; thread died")
|
||||||
|
|
||||||
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
|
proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
|
||||||
action: proc (input: TIn): TOut {.thread.}
|
action: proc (input: TIn): TOut {.thread.}
|
||||||
|
|
|
||||||
|
|
@ -222,11 +222,14 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =
|
||||||
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
|
llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))
|
||||||
|
|
||||||
proc peek*[TMsg](c: var TChannel[TMsg]): int =
|
proc peek*[TMsg](c: var TChannel[TMsg]): int =
|
||||||
## returns the current number of messages in the channel `c`.
|
## returns the current number of messages in the channel `c`. Returns -1
|
||||||
|
## if the channel has been closed.
|
||||||
var q = cast[PRawChannel](addr(c))
|
var q = cast[PRawChannel](addr(c))
|
||||||
if q.mask != ChannelDeadMask:
|
if q.mask != ChannelDeadMask:
|
||||||
lockChannel(q):
|
lockChannel(q):
|
||||||
result = q.count
|
result = q.count
|
||||||
|
else:
|
||||||
|
result = -1
|
||||||
|
|
||||||
proc open*[TMsg](c: var TChannel[TMsg]) =
|
proc open*[TMsg](c: var TChannel[TMsg]) =
|
||||||
## opens a channel `c` for inter thread communication.
|
## opens a channel `c` for inter thread communication.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ discard """
|
||||||
template myAssert(cond: expr) =
|
template myAssert(cond: expr) =
|
||||||
when rand(3) < 2:
|
when rand(3) < 2:
|
||||||
let c = cond.astToStr
|
let c = cond.astToStr
|
||||||
{.warning: "code activated: " & c.}
|
|
||||||
if not cond:
|
if not cond:
|
||||||
echo c, "ugh"
|
echo c, "ugh"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ proc runThreadTests(r: var TResults, options: string) =
|
||||||
|
|
||||||
test "tactors"
|
test "tactors"
|
||||||
test "threadex"
|
test "threadex"
|
||||||
|
test "trecursive_actor"
|
||||||
#test "threadring"
|
#test "threadring"
|
||||||
#test "tthreadanalysis"
|
#test "tthreadanalysis"
|
||||||
#test "tthreadsort"
|
#test "tthreadsort"
|
||||||
|
|
|
||||||
19
tests/threads/trecursive_actor.nim
Normal file
19
tests/threads/trecursive_actor.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
discard """
|
||||||
|
outputsub: "0"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import actors
|
||||||
|
|
||||||
|
var
|
||||||
|
a: TActorPool[int, void]
|
||||||
|
createActorPool(a)
|
||||||
|
|
||||||
|
proc task(i: int) {.thread.} =
|
||||||
|
echo i
|
||||||
|
if i != 0: a.spawn (i-1, task)
|
||||||
|
|
||||||
|
# count from 9 till 0 and check 0 is somewhere in the output
|
||||||
|
a.spawn(9, task)
|
||||||
|
a.join()
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue