2010-06-11 2 views
5

Следующий тестовый код (F #) не возвращает результат я бы ожидать:.NET 4 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).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 взаимно исключают счетчик, и, следовательно, для того, чтобы вернуться насчитывает 1,000,000, но вместо этого он возвращает меньшие значения, как если бы не было взаимного исключения.

Любые идеи, что не так?

ответ

3

EDIT: У Stephen Swensen есть доступ к прямой ссылке 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 
+0

Спасибо. Похоже, что поля в классах не копируются, а все остальное. Если это правильно, это также имеет последствия для других приложений, таких как сложная арифметика, где вы хотите избежать копирования структур (а C# в настоящее время намного быстрее, чем F #). –

8

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

+0

Можно ли это решить? –

10

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

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