簡體   English   中英

如何使用 F# 鎖定對象?

[英]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 = 8

val 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM