2010-03-04 5 views
4

Java의 동시성에 대한 Sun의 자습서에서 예를 재 작성하고 싶습니다. 원래 코드는 다음과 같습니다. http://java.sun.com/docs/books/tutorial/essential/concurrency/deadlock.html스칼라에서 '교착 상태'

이 코드는 올바르지 않습니다. 그것은 주석이 나타내는 곳에서 멈 춥니 다. 아무도 이것을 고칠 수 있습니까? 미리 감사드립니다.

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" 
} 
+0

교착 상태를 재현하는 데 필요한 최소 코드까지 줄일 수 있습니까? – Andrey

답변

5

첫 번째 실수는 result == true입니다. result = true

while 조건에서 true 값을 삭제해야합니다. 그것은 영향력이 없습니다.

BowTest 개체의 경우 g.bow(a) 지침 Thread.sleep(1000) 뒤에 추가해야 배우가 메시지에 응답하는 데 충분한 시간을 줄 수 있습니다.

이렇게하면 코드가 작동합니다. 그러나 여전히 교착 상태에 빠져 있습니다. g.bow(a)a.bow(g)으로 변경하면 실행이 중단됩니다. 이는 receive 블록으로 인해 발생합니다. 각 액터는 보우 드 메시지를 기다리고 있지만 보우 백 메시지에는 응답 할 수 없습니다.

메시지에 응답 할 때 액터가 지정된 메시지를받을 것이라는 확신이있는 경우에만 receive 블록을 사용해야합니다. 그러나 대개 이것은 배우를 디자인하는 좋은 습관이 아닙니다. 그들은 막아서는 안됩니다. 배우의 주요 목적은 메시지에 최대한 빨리 응답하는 것입니다. 큰 작업을 수행해야한다면 futures을 사용해야하지만,이 경우에는 필요하지 않습니다.

해결 방법은 목록에서 절을하는 사람을 유지하는 것입니다. 배우가 사람을 숙이게되면 목록에 추가됩니다. 배우가 목록에있는 사람에 의해 절을하면 해당 사람이 목록에서 제거됩니다.

 

    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) 
     } 
    } 
 
+0

글쎄, 내 대답보다 훨씬 더 많이 갔다. – Calum

+0

고맙습니다. 이것은 실제로 해결책입니다. 여기에 붙여 넣은 코드는 다소 복잡합니다. 왜냐하면 제가 튜닝하기 때문입니다. – Xenofex

+0

이런 종류의 상호 작용을 완전히 시뮬레이션하려면 훨씬 복잡한 모델로 이어질 것 같습니다. – Xenofex

0

교착 상태가 아니며 단순한 버그라고 생각합니다. 귀하의 코멘트 아래 두 라인 :

received == true

= 대신 ==해야한다. 나는 깊이 보지 못했습니다 (이것은 나에게 튀어 나왔습니다). 그러나 처럼 보입니다.