2010-06-11 10 views
5

El siguiente código de prueba (F #) no devuelve el resultado que cabe esperar:.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 

yo esperaría que la SpinLock excluyen mutuamente a la barra y, por lo tanto, para que vuelva cuenta de 1,000,000 pero, en cambio, devuelve valores más pequeños como si no existiera una exclusión mutua.

¿Alguna idea de qué pasa?

Respuesta

3

EDITAR: Stephen Swensen tiene una manera de acceder directamente a un estilo de ref SpinLock a continuación. ! devuelve una copia de las estructuras, por lo que no debería usarse en este caso.

Usted puede envolver SpinLock en una clase funciona (He intentado utilizar un SpinLock estática e inmutable en vano)

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

Gracias. Parece que los campos de las clases no se copian sino todo lo demás. Si eso es correcto, también tiene implicaciones para otras aplicaciones, como la aritmética compleja, donde se desea evitar copiar estructuras (y C# es actualmente mucho más rápido que F #). –

8

SpinLock es un tipo de valor. Cuando desreferencia su variable spinLock (! SpinLock), la estructura se copió, y el bloqueo que ingresa/sale ahora es diferente.

+0

¿Se puede solucionar esto? –

10

La razón por la cual se está copiando la estructura SpinLock es debido! es una función: las estructuras se copian cuando se pasan como argumentos a una función o se devuelven desde una función (o cualquier otro tipo de asignación para el caso). Sin embargo, si accede directamente al contenido de la celda de referencia, no se realiza ninguna copia.

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