.NET 4 SpinLock - PullRequest
       5

.NET 4 SpinLock

5 голосов
/ 11 июня 2010

Следующий тестовый код (F #) не возвращает ожидаемый результат:

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

Я бы ожидал, что SpinLock взаимно исключит счетчик и, следовательно, возвращает 1000000, но вместо этого возвращает меньшие значения, как если бы взаимного исключения не происходило.

Есть идеи, что случилось?

Ответы [ 3 ]

10 голосов
/ 12 июня 2010

Причина, по которой копируется структура SpinLock, заключается в том, что!является функцией: структуры копируются, когда передаются в качестве аргументов функции или возвращаются из функции (или любого другого типа присвоения по этому вопросу).Однако, если вы обращаетесь к содержимому ячейки ссылки напрямую, копирование не происходит.

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
8 голосов
/ 11 июня 2010

SpinLock является типом значения.Когда вы разыменовываете переменную spinLock (! SpinLock), структура копируется, и блокировка, которую вы вводите / выходите, теперь отличается.

3 голосов
/ 12 июня 2010

EDIT: У Стивена Свенсена есть способ прямого доступа к ссылочному стилю SpinLock ниже. ! возвращает копию структур, поэтому не должен использоваться в этом случае.

Вы можете обернуть SpinLock в класс, который работает (я пытался использовать статический и неизменный SpinLock безрезультатно)

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...