Can’t figure out how to resolve following problem: I have a few actors (workers) that execute tasks in some way when they recieve (I mean react) them. A main actor (foreman) controls this process and can recieve task to stop work. In this case main actor must stop creating new tasks and wait when workers will finish all existing tasks and only then main actor should exit.
import actors.Actor
import actors.Actor._
class Foreman extends Actor{
val workerA = new WorkerA
val workerB = new WorkerB
val workerC = new WorkerC
self.link(workerA)
self.link(workerB)
self.link(workerC)
def act{
workerA.start
workerB.start
workerC.start
// adding tasks to workers somehow
//...
loop{
case ResultOfTask(res) => //...
case Stop => //workers mustn't immediately stop but must finish their tasks and then exit
case ProductionAccident => //...
}
}
}
case class Task(activity:String)
case class ResultOfTask(result:String)
trait Worker extends Actor{
def act{
loop{
react{
case Task(activity) => sender ! processTask(activity)
}
}
}
def processTask(activity:String):ResultOfTask
}
To solve this I wrote following code:
def condition = workerA.getState!=State.Suspended && workerB.getState!=State.Suspended && workerC.getState!=State.Suspended && mailboxSize == 0
case Stop => {
if(condition) exit("sweet dreams") else continue
}
to check if main actor should exit. Another variant to have counder in “Worker” trait, increment it when worker recieves message and decrement when it reponses.
trait Worker extends Actor {
private var count = 0
def act {
loop{
react{
case Task(activity) => {
count += 1
sender ! processTask(activity)
count -= 1
}
}
}
}
def hasDoneAllTasks = count == 0
def processTask(activity: String): ResultOfTask
}
And “condition” function in “Foreman” will be
def condition = workerA.hasDoneAllTasks && workerB.hasDoneAllTasks && workerC.hasDoneAllTasks && mailboxSize == 0
I hope there are better solutions and you will propose them.
If the foreman always expects an answer from the workers, the solution is easy: the foreman maintains a counter, and each time it sends a message it increments it and each time it receives one from a worker it decrements it. Any time the counter is zero it is free to stop itself (assuming that no-one else sends messages to the workers).
If the foreman does not always expect an answer from the workers, you can make this the case by having a no-content message
and having the workers reply with that when they’re finished. Then, see above.
If the foreman is not the only one talking to the workers, or you want there to be less chatter in the background, then the foreman and the workers will have to negotiate. The foreman can send
and the workers will do something graceful and reply with
Donewhen they’re done. When the foreman receives as manyDonemessages as it has sentRequestStops, it is free to exit.