.NET 4 SpinLock

爷,独闯天下 提交于 2019-12-10 15:10:03

问题


The following test code (F#) is not returning the result I'd expect:

let safeCount() =
  let n = 1000000
  let counter = ref 0
  let spinlock = ref <| SpinLock(false)
  let run i0 i1 () =
    for i=i0 to i1-1 do
      let locked = ref false
      try
        (!spinlock).Enter locked
        if !locked then
          counter := !counter + 1
      finally
        if !locked then
          (!spinlock).Exit()
  let thread = System.Threading.Thread(run 0 (n/2))
  thread.Start()
  run (n/2) n ()
  thread.Join()
  !counter

I'd expect the SpinLock to mutually exclude the counter and, therefore, for it to return counts of 1,000,000 but, instead, it returns smaller values as if no mutual exclusion is occurring.

Any ideas what's wrong?


回答1:


EDIT: Stephen Swensen has a way to directly access a ref style SpinLock below. ! returns a copy of structs so should not be used in this case.

You can wrap SpinLock in a class it works (I tried using a static and immutable SpinLock to no avail)

type SpinLockClass() =
    let s = System.Threading.SpinLock(false)
    member x.Enter locked = s.Enter(locked)
    member x.Exit() = s.Exit()

let safeCount() =
  let n = 1000000
  let counter = ref 0
  let spinlock = SpinLockClass()
  let run i0 i1 () =
    for i=i0 to i1-1 do
      let locked = ref false
      try
        spinlock.Enter locked
        if !locked then
          counter := !counter + 1
      finally
        if !locked then
          spinlock.Exit()
  let thread = System.Threading.Thread(run 0 (n/2))
  thread.Start()
  run (n/2) n ()
  thread.Join()
  !counter



回答2:


The reason why the SpinLock struct is being copied is because ! is a function: structs are copied when passed as arguments to a function or returned from a function (or any other kind of assignment for that matter). However, if you access the contents of the ref cell directly, no copying takes place.

let safeCount() =
  let n = 1000000
  let counter = ref 0
  let spinlock = ref <| SpinLock(false)
  let run i0 i1 () =
    for i=i0 to i1-1 do
      let locked = ref false
      try
        spinlock.contents.Enter locked
        if !locked then
          counter := !counter + 1
      finally
        if !locked then
          spinlock.contents.Exit()
  let thread = System.Threading.Thread(run 0 (n/2))
  thread.Start()
  run (n/2) n ()
  thread.Join()
  !counter



回答3:


SpinLock is a value type. When you dereference your spinLock variable (!spinLock), the struct got copied, and the lock you enter/exit is now different.



来源:https://stackoverflow.com/questions/3019446/net-4-spinlock

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!