How can I add scala actors to an existing program without interfering with the normal termination behavior?
Asked Answered
P

2

6

This program, after executing main(), does not exit.

object Main
{
    def main(args: Array[String]) {
        ... // existing code
        f()
        ... // existing code
    }
    def f() {
        import scala.actors.Actor._
        val a = actor {
            loop {
                react {
                case msg: String => System.out.println(msg)
                }
            }
        }
        a ! "hello world"
    }
}

Because of this unexpected side-effect, using actors can be viewed as intrusive.

Assuming the actors must continue to run until program termination, how would you do to preserve original behavior in all cases of termination?

Proscenium answered 21/2, 2010 at 11:44 Comment(0)
M
7

In 2.8 there's a DaemonActor class that allows this. In 2.7.x I you could hack in a custom scheduler that doesn't prevent shutdown even if there are still live actors, or if you want an easy way you could call System.exit() at the end of main.

If you think of an actor as kind of a light-weight thread, much of the time you want a live actor to prevent program termination. Otherwise if you have a program that does all of its work in actors, you'd need to have something on the main thread just to keep it alive until all the actors finish.

Mose answered 21/2, 2010 at 13:11 Comment(0)
S
4

After the main thread in the above example completed, the program still had a non-daemon thread running the actor. It is usually a bad idea to brutally terminate running threads using Thread.destroy() or System.exit() for results may be very bad for your program including, but not limited to, data corruption and deadlocks. That is why Thread.destroy() and alike methods were deprecated in Java for the first place. The right way would be to explicitly implement termination logic in your threads. In case of Scala actors that boils down to sending a Stop message to all running actors and make them quit when they get it. With this approach your eample would look like this:

object Main
{
    case object Stop
    def main(args: Array[String]) {
        ... // existing code
        val a = f()
        a ! "hello world"
        ... // existing code
        a ! Stop
    }
    def f() = {
        import scala.actors.Actor._
        actor {
            loop {
                react {
                   case msg: String => System.out.println(msg)
                   case Stop => exit()
                }
            }
        }
    }
}
Snooze answered 22/2, 2010 at 5:59 Comment(1)
Alas, managing actor lifetime manually is what I wanted to avoid... It's intrusive, as I have to change main().Proscenium

© 2022 - 2024 — McMap. All rights reserved.