Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET 4 SpinLock

Tags:

.net

f#

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?

like image 399
J D Avatar asked Jun 11 '10 00:06

J D


Video Answer


2 Answers

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
like image 115
Stephen Swensen Avatar answered Nov 15 '22 09:11

Stephen Swensen


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.

like image 26
Dmitry Lomov Avatar answered Nov 15 '22 11:11

Dmitry Lomov