2009-08-22 6 views
2

私はScalaを学び、今のところ素晴らしい言語を見つけようとしています。私は"Beginning Scala"からDavid Pollakによって学びます。第3章では、同期ブロックのないマルチスレッドコードを書く方法を示したこのコードがあります(このコードは本からコピーされています。Apress siteからダウンロードできます。私はここで法律を破るつもりはありません)。このコードに潜在的な飢餓があるのですか、それとも私だけですか?

私が理解から
 
import java.util.concurrent.atomic.{AtomicReference => AtomR, AtomicLong} 
import java.util.Random 
import scala.collection.immutable.TreeHashMap 

object Multics { 
    type MT = Map[String, Int] 

    val info: AtomR[MT] = new AtomR(TreeHashMap.empty) 
    val clashCnt = new AtomicLong 

    def main(argv: Array[String]) { 
    runThread { 
     repeatEvery(1000) { 
     println("Clash Count: "+clashCnt+" Total: "+ 
       info.get.foldLeft(0)(_ + _._2)) 
     } } 

    for (i old + (name -> 0)} 
     repeatEvery(ran.nextInt(100)) { 
     doSet(info){old => old + (name -> (old(name) + 1))} 
     cnt = cnt + 1 
     if (cnt != info.get()(name)) 
      throw new Exception("Thread: "+name+" failed") 
     } } 
    } 

    def runThread(f: => Unit) = 
    (new Thread(new Runnable {def run(): Unit = f})).start 

    def doSet[T](atom: AtomR[T])(update: T => T) { 
    val old = atom.get 
    if (atom.compareAndSet(old, update(old)))() 
    else { 
     clashCnt.incrementAndGet 
     doSet(atom)(update) 
    } 
    } 

    def repeatEvery(len: => Int)(body: => Unit): Unit = { 
    try { 
     while(true) { 

     Thread.sleep(len) 
     body 
     } 
    } catch { 
     case e => e.printStackTrace; System.exit(1) 
    } 
    } 
} 

、機能doSetの潜在的な飢餓問題(不運なスレッドは常に衝突し、StackOverflowExceptionがの原因となることがあります)があります。もしそうなら、この問題を解決するためにこのコードをどのように改善することができますか?

+0

あなたのコードは完全には完璧ではありません(死んだことは、それがコンパイルされないという事実です;-)。 http://uys.be/Multics.scalaで置き換えてください(まだ質問を編集するのに十分なポイントがありません)。 – opyate

答えて

2

まず、本の例から貼り付けたコードの大きなチャックがないと思います。それはあなたの質問を理解することを非常に困難にします。

第2に、doSet()は再帰的に何度も呼び出される可能性がありますが、この場合は1つの保存猶予:テール再帰のためStackOverflowExceptionは発生しません。 doSet()は、関数の終わりに再帰的に呼び出されます(再帰呼び出しの後で処理はこれ以上行われません)。また、スタックオーバーヘッドなしに最適化されるようにオーバーライドすることもできません。

2.8.0には、@ scala.annotation.tailrecというアノテーションがあり、これをdefで使用すると、def内の再帰呼び出しが本当に末尾再帰であることが保証されます。

+0

コード全体がペーストされます。スクロールするだけです。 –

+0

私はあなたの答えを正しく理解していれば、ここで飢えている可能性は高いですが、StackOverflowExceptionによっても止まらない無限ループが発生します。 –

+0

私が言っていたことは、doSet()が繰り返し回帰的に呼び出されるかもしれないが、スタックフレームの消費がないので、スタックオーバーフローの危険はないということです。スレッドスターベーションに関しては、あなたの飢餓の定義に本当に依存します。今日のハードウェアでは、2000年のスレッドが2,3秒以上枯渇してしまったことは実際には分かりません。 –

0

ロックの代わりにCompare and Swap(http://en.wikipedia.org/wiki/Compare-and-swap)を使用しているようです。

このアプローチの一般的な考え方は、値を一貫して設定するまでループすることです。

飢餓問題がある場合は、これについて十分にはわかりません。私の推測では、理論的には飢餓の問題がありますが、実際にはうまくいくでしょう。

関連する問題