tags:

views:

114

answers:

2

I want to rewrite in scala the example from Sun's tutorial about concurrency in java. The original code is here: http://java.sun.com/docs/books/tutorial/essential/concurrency/deadlock.html

This code is incorrect. It freezes at where the comment indicates. Could anyone correct this? Thanks in advance.

import scala.actors.Actor

class Person(val name: String) extends Actor {

  def bow(other: Person) {
    other ! Bow(this)
  }

  private def bowBack(backTo: Person) {
    println(this.name + " is bowing back to " + backTo.name)
    backTo ! Bowed(this)
  }

  def act() {
    while (true) {
      receive {
        case Bow(p) =>
          println(this.name + " is bowing to " + p.name)
          p ! BowBack(this)
          println("    wating for bowing back...")
          var received = false
          while (true && received == false) {
            receive {    //blocked here
              case Bowed(other) if p == other =>
                println(" ... " + this.name + " has bowed to " + other.name)
            received == true
            }
          }
          println(this.name + " has bowed to " + p.name)
        case BowBack(p) =>
          println(this.name + " is bowing back to " + p.name)
          p ! Bowed(this)
        case "EXIT" => return
        case x => println(x)
      }
    }
  }
}

abstract case class Action()
case class Bow(person: Person) extends Action
case class BowBack(person: Person) extends Action
case class Bowed(person: Person) extends Action

object BowTest extends Application {
  val a = new Person("Alphone")
  val g = new Person("Gaston")
  a.start()
  g.start()

  a ! Bow(g)
  //g.bow(a)

  a ! "EXIT"
  g ! "EXIT"
}
A: 

Not deadlock, just a plain ol' bug, I think. Two lines under your comment:

received == true

This should be = instead of ==. I've not looked in depth (this sprung out at me) but it looks like this would fix your issue.

Calum
+4  A: 

The first mistake is that you wrote result == true. This should be changed to result = true

You should delete the true value from the while condition. It has no influence.

In the BowTest object you should add after the g.bow(a) instruction Thread.sleep(1000) to give actors enough time to respond to the messages.

In this way your code should work. But still it has a deadlock. If you will change g.bow(a) in a.bow(g) the execution will freeze. This is caused by the receive block. Each actor is waiting for the Bowed message, but they cannot respond to the BowBack message.

When you are responding to a message, you should use receive block only if you are sure that the actor will get the specified messages. But usually this is not a good practice in designing actors. They should not block. The main purpose of an actor is to respond as fast as possible to a message. If you have to do a big task you should use futures, but in this case is not required.

A solution will be to retain the persons which are bowed in a list. When the actor have to bow a person it adds it in the list. When the actor is bowed by a person which is in the list, it removes that person from the list.


    while (true) {
      react {
        case Bow(p) =>
          println(this.name + " is bowing to " + p.name)
          addPersonToBowList(p)
          p ! BowBack(this)

        case Bowed(other) if isPersonInBowList(other) =>
                println(" ... " + this.name + " has bowed to " + other.name)
                removePersonFromBowList(other)
        case BowBack(p) =>
          println(this.name + " is bowing back to " + p.name)
          p ! Bowed(this)
        case "EXIT" => exit()
        case x => println(x)
      }
    }

Ionel Bratianu
Well you certainly went a lot further than I did with my answer!
Calum
Thank you very much. This is indeed a solution. The code pasted here is somewhat messy, because I'm tuning it.
Xenofex
To fully simulating this kind of interaction seems to lead to a much more complicated model.
Xenofex