2017-10-16 4 views
1

考える例外: MVARを更新すると、例外

λ: >:t putMVar 
putMVar :: MVar a -> a -> IO() 

λ: >:t x 
x :: IO (MVar [Char]) 
まだそれはなぜそれが失敗したとどのように私はと xを更新することができます

λ: >x >>= \y -> putMVar y "foo" 
:^?^? 

*** Exception: thread blocked indefinitely in an MVar operation 

を失敗しました:私はputMVarを呼び出そうとしました

λ: >let x = Control.Concurrent.MVar.newMVar "" 
λ: >:t x 
x :: IO (MVar [Char]) 

"foo"ではなく""

+1

私はあなたが新しいMVarを値で作成すると思います。あなたがそれを入れる前にその値を抽出する必要があります! – epsilonhalbe

+2

これは意図されています: 'MVar'のセマンティクスは、mutexで保護された1位のキューの1つです。 '" "を含む完全なキューを作成します。キューを最初に 'takeMVar'で空にするまで、他のものをキューに入れることはできません。さもなければ 'putMVar'は他の誰かが最初にキューを空にするのを待ちます。あなたのケースでは、GHCは誰もキューを空にすることができないことに気づき、永遠に詰まる代わりに例外をトリガーします(ランタイムは親切にしようとしています。 – chi

答えて

6

xMVarではありません。これはMVarを作成するアクションです。つまり、newMVar ""の別の名前です。

x >>= \y -> putMVar y "foo"は、MVarを作成し、yという名前のアクションです。その後、MVar"foo"を入力しようとします。ただし、yにはすでに""が含まれているため、putMVarブロックになります。 yはこのアクションのローカル変数であり、他の誰もアクセスできず、読者が存在しないため、単に永遠にブロックされるわけではありません。 putMVarはこの状況を検出し(デッドロック)、代わりに例外をスローします。これはxMVarなり

x <- newMVar "" 

:あなたの代わりに何をすべき

で始まるです。

takeMVar x 

をワンステップで既存の値を置き換えるサポートしていません(

putMVar x "foo" 

MVarを新たな価値を置く;:

その後、古い値("")を取り出すことができます

6

のは、ドキュメントアップを見てみましょう:

data MVar a 

MVAR(発音は "EM-VAR")は、同時実行スレッド間の の通信に使用される同期変数、です。これは、 ボックスと考えることができます。空でもフルでもかまいません。

newMVar :: a -> IO (MVar a) 

供給値を含むMVARを作成します。

putMVar :: MVar a -> a -> IO() 

MVARに値を入れてください。現在MVarがいっぱいの場合、putMVarは が空になるまで待機します。

putMVarの2つの別の重要な特性があります。

putMVarは、シングル・ウェイクアップです。つまり、複数のスレッド がputMVarでブロックされ、MVarが空になると、ただ1つのスレッドだけが を起動します。ランタイムは、起床したスレッドがputMVar操作を完了することを保証します。 複数のスレッドがMVarでブロックされている場合、 はFIFO順にウェイクアップされます。これは、MVarsを使用して構築された抽象概念の公平性を提供するのに便利です( )。

メルポメンズの答えに正しい説明が含まれています。私は引用した文書のために私の答えをここに残しておきます。

関連する問題