1

I want to create a cacheline sized struct wrapping a mutable, volatile int64 in F#. I’ve tried various struct definitions including the one below, but can't get anything to compile.

[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct1 (initVal:int64) =
    [<VolatileField>]
    let mutable value = initVal
    member x.Value 
        with get () = value
        and set(valIn) = value <- valIn

which gives this error: "Structs cannot contain value definitions because the default constructor for structs will not execute these bindings. consider adding additional arguments to the primary constructor for the type". I can't see what additional arguements I could add to the primary constructor above.

Any ideas?

DaveShaw
  • 52,123
  • 16
  • 112
  • 141
Ian Spratt
  • 261
  • 2
  • 5

2 Answers2

1

The struct definition could be

[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
    [<FieldOffset(0)>]
    val mutable value : int64
    new(initVal:int64) = { value = initVal }
    member x.Value
        with get() = x.value
        and set(valIn) = x.value <- valIn

but then, [<VolatileField>] is not allowed on val bindings and structs can't contain let bindings.

TL;DR: AFAIK this is impossible in F#

As pointed out by @V.B. you could use Interlocked which gives a superset of volatiles guarantees (stronger guarantees ≈ more overhead). It might then be better to privateize value to prevent (accidental) writes circumventing the barrier:

[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
    [<FieldOffset(0)>]
    val mutable private value : int64
    new(initVal:int64) = { value = initVal }
    member public x.Value
        with get() = Interlocked.Read(&x.value)
        and set(valIn) = Interlocked.Exchange(&x.value, valIn) |> ignore
CaringDev
  • 8,391
  • 1
  • 24
  • 43
0

Interlocked gives similar guarantees as volatile, see this question.

open System.Threading
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
    [<FieldOffset(0)>]
    val mutable value : int64
    new(initVal:int64) = { value = initVal }
    member x.Value
        with get() = Interlocked.Read(&(x.value))
        and set(valIn) = Interlocked.Exchange(&(x.value),valIn) |> ignore
Community
  • 1
  • 1
V.B.
  • 6,236
  • 1
  • 33
  • 56