[英]how to lock an object using F#?
假設我有以下代碼:
let a = ref 4.
printfn "1) a = %g" !a
let t1 = System.Threading.Thread (fun () ->
lock a (fun () ->
printfn "locked"
System.Threading.Thread.Sleep 1000
printfn "unlocked") )
t1.Start()
System.Threading.Thread.Sleep 100
a := 8.
printfn "2) a = %g" !a
這給出了以下結果:
1) a = 4
鎖定
2) a = 8val a : float ref = {contents = 8.0;}
val t1 : System.Threading.Thread解鎖
為什么a
等於8.
當我鎖定它時? 是否可以使用可變值和引用鎖定記錄?
PS:我需要鎖定一個同時被我和 WCF 訪問的對象。
我同意@Dmitry 的觀點,即使用lock k (fun () -> ...)
並不意味着您可以防止k
發生突變; 它確實意味着您獲得了一個密鑰k
來訪問一個對象。 因為鍵是唯一的,所以您可以互斥地訪問對象以避免得到錯誤的結果。
根據你的例子中,在運行此下面的代碼在調試模式下導致的1,3或6的結果a
任意。 這些值可以通過當一個線程訪問的舊值的情況來解釋a
,而另一個線程試圖更新單元格。
let a = ref 4;;
printfn "1) a = %i" !a
let t1 = System.Threading.Thread (fun () ->
printfn "locked in thread 1"
a:= !a + 2
printfn "unlocked in thread 1"
)
let t2 = System.Threading.Thread (fun () ->
printfn "locked in thread 2"
a:= !a - 3
printfn "unlocked in thread 2"
)
t1.Start()
t2.Start()
System.Threading.Thread.Sleep 1000 // wait long enough to get the correct value
printfn "2) a = %i" !a;;
System.Console.ReadKey() |> ignore;;
為了確保正確的結果(應該是 3),您可以引入一個對象monitor
,並且任何想要更新a
線程都必須首先獲取monitor
:
let monitor = new Object()
let a = ref 4;;
printfn "1) a = %i" !a
let t1 = System.Threading.Thread (fun () ->
printfn "locked in thread 1"
lock monitor (fun () -> a:= !a + 2)
printfn "unlocked in thread 1"
)
let t2 = System.Threading.Thread (fun () ->
printfn "locked in thread 2"
lock monitor (fun () -> a:= !a - 3)
printfn "unlocked in thread 2"
)
t1.Start()
t2.Start()
System.Threading.Thread.Sleep 1000 // wait long enough to get the correct value
printfn "2) a = %i" !a;;
System.Console.ReadKey() |> ignore;;
您似乎誤解了鎖定的工作原理。
在 C# 中,“lock 關鍵字確保一個線程不會進入代碼的臨界區,而另一個線程在臨界區。如果另一個線程試圖輸入鎖定的代碼,它將等待、阻塞,直到對象被釋放。 ” 所以它不能保護鎖定的對象免受突變。 在 F# 中, lock
工作方式完全相同。
順便說一句,AFAIK, lock
只是Monitor類的一個糖。
根據 Don Syme 的說法,鎖函數的定義實際上是這樣的:
open System.Threading
let lock (lockobj:obj) f =
Monitor.Enter lockobj
try
f()
finally
Monitor.Exit lockobj
更新:因為鎖定不會使對象成為只讀並且因為您無法控制 WPF 代碼,所以您的問題的解決方案涉及將線程同步添加到 WPF 訪問的屬性(並盡量不阻止 UI 線程)或在 UI 上安排工作線程或其他。 在不知道確切問題的情況下很難說。 好吧,好消息是網絡上有大量信息。
UPDATE2:哎呀,我讀過“WPF”而不是“WCF”。 嗯,這讓你的生活更輕松。 您只需要將線程同步添加到 WCF 方法實現中,並且在大多數情況下,您無需擔心阻塞它們。 所以只需小心地為所有相關代碼添加鎖......
情節扭曲 - 使用 ref 單元格,您不需要額外的 obj 來充當鎖,即更改
一:= 8。
到
鎖定 a(有趣的 _ -> a := 8。)
將確保兩個線程都阻塞並等待單元變為可用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.