私は最近、 に関して多くの質問をしましたが、TVar
ライブロックについてはまだ懸念があります。
だから私はこの構造を考えました:
- 各トランザクションには一意の優先度が割り当てられます (おそらく、作成順に割り当てられます)。
- トランザクションは、アクセスするデータに対して読み取り/書き込みロックを取得しようとします。当然、同時読み取りは問題ありませんが、1 つの書き込みロックが他のすべて (読み取りと書き込みの両方) を除外します。
- トランザクション A がトランザクション B よりも優先度が高いとします。A がロックを保持している場合、B は待機しますが、B がロックを保持しており、A がそれを望んでいる場合、B はロックから起動され、A はそれを取得し、トランザクション B は ( のように
TVar
) 再起動します。ただし、B は再試行の現在の優先度を維持します。 - ロックが解放され、待機中のトランザクションがある場合、最も優先度の高いトランザクションに移動し、残りは引き続き待機します。
このシステムは、デッドロックを防ぐだけでなく、( とは異なり) 飢餓も防ぐと私は信じていTVar
ます。そのようなシステムを実装した人がいるかどうか疑問に思っていました.
もちろん、このようなアプローチは、ユーザーが優先順位を指定できるように簡単に拡張できます。
優先度は、優先度が高いペアの可能性がありますが(user_supplied_prio, auto_increment)
、user_supplied_prio
同じ優先度のタスクが FIFO 順で解決されます。
コメント/解決策:
実際、考えてみると、Haskell には、IORef
すべてのデータをラップしたものを使用し、atomicModifyIORef
. これatomicModifyIORef
により、トランザクションが順番に適用されます。ただし、これはデータ構造がシーケンシャル (事実上 1 つのスレッドに制限されている) であることを意味すると考えるかもしれませんが、実際には遅延のために並列です。
これを説明するために、高価な関数を考えてみましょうf
。Data.Map
これをキー「foo」を持つデータに適用します。
これは に置き換え(foo -> x)
られ(foo -> future(f x))
ます。(f x)
このスレッドは、実際に何が何であるかを解決し続けますが、それまでの間、「バー」に g を適用できます。g を "bar" に適用すると "foo" の結果は必要ないため、これを同時に解決できます。
デッドロックや飢餓は発生せず、最終的にはすべてのトランザクションが処理されます (おおよそ、受信した順序で)。