假设我有以下代码:
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
Run Code Online (Sandbox Code Playgroud)
这给出了以下结果:
1)a = 4
锁定
2)a = 8val a:float ref = {contents = 8.0;}
val t1:System.Threading.Thread解锁
当我锁定它时为什么a等于8.?是否可以使用可变值和refs锁定记录?
PS:我需要锁定一个对象,这个对象既可以由我访问,也可以由WCF同时访问.
pad*_*pad 13
我同意@Dmitry的使用lock k (fun () -> ...)并不意味着你要防止变异k; 它确实意味着您获得了k访问对象的密钥.由于密钥是唯一的,因此您可以对对象进行互斥访问,以避免出现错误结果.
根据您的示例,在调试模式下运行以下代码会导致a任意结果为1,3或6 .这些值可以通过一个线程访问旧值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;;
Run Code Online (Sandbox Code Playgroud)
为了确保正确的结果(应该是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;;
Run Code Online (Sandbox Code Playgroud)
Dmi*_*try 10
你似乎误解了锁定是如何工作的.
在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
Run Code Online (Sandbox Code Playgroud)
更新:因为锁定不会使对象成为只读,并且因为您无法控制WPF代码,所以您的问题的解决方案涉及向WPF访问属性添加线程同步(并尝试不阻止UI线程)或在UI上安排工作线程或其他.在不知道确切问题的情况下很难分辨.嗯,好消息是网上有大量的信息.
UPDATE2:哎呀,我读过"WPF"而不是"WCF".嗯,这会让你的生活更轻松.您只需要将线程同步添加到WCF方法实现中,在大多数情况下,您可以不再担心阻止它们.所以只需仔细添加锁定到所有相关代码......