How to atomic store & load an interface in golang?
Asked Answered
C

4

8

I want to write some code like this:

var myValue interface{}

func GetMyValue() interface{} {
    return atomic.Load(myValue)
}

func StoreMyValue(newValue interface{}) {
    atomic.Store(myValue, newValue)
}

It seems like that i can use LoadUintptr(addr *uintptr) (val uintptr) and StoreUintptr(addr *uintptr, val uintptr) in atomic package to achive this,but i do not know how to convert between uintptr,unsafe.Pointer and interface{}.

If i do it like this:

var V interface{}

func F(v interface{}) {
    p := unsafe.Pointer(&V)
    atomic.StorePointer(&p, unsafe.Pointer(&v))
}

func main() {
    V = 1
    F(2)
    fmt.Println(V)
}

the V will always be 1

Context answered 11/12, 2017 at 10:34 Comment(0)
U
10

If I'm not mistaken you want atomic Value. You can store and fetch values atomically with it (signatures are interface{} but you should put same type into it). It does some unsafe pointer stuff under the hood like what you wanted to do.

Sample from docs:

var config Value // holds current server configuration
// Create initial config value and store into config.
config.Store(loadConfig())
go func() {
        // Reload config every 10 seconds
        // and update config value with the new version.
        for {
                time.Sleep(10 * time.Second)
                config.Store(loadConfig())
        }
}()
// Create worker goroutines that handle incoming requests
// using the latest config value.
for i := 0; i < 10; i++ {
        go func() {
                for r := range requests() {
                        c := config.Load()
                        // Handle request r using config c.
                        _, _ = r, c
                }
        }()
}
Uppity answered 11/12, 2017 at 13:11 Comment(0)
U
1

Here's a way to use atomic.StorePointer and atomic.LoadPointer (based on your example):

package main

import (
    "fmt"
    "sync/atomic"
    "unsafe"
)

var addr unsafe.Pointer

func GetMyValue() *interface{} {
    return (*interface{})(atomic.LoadPointer(&addr))
}

func StoreMyValue(newValue *interface{}) {
    atomic.StorePointer(&addr, unsafe.Pointer(newValue))
}

func main() {
    var i interface{}
    i = 1
    StoreMyValue(&i)
    fmt.Println("before:", *GetMyValue())
    i = 2
    StoreMyValue(&i)
    fmt.Println("after", *GetMyValue())
}

Playground link

Note that this will not make your object thread-safe. Only the pointer is stored/loaded atomically. Also, I would avoid using interface{} and prefer concrete types whenever possible.

Uball answered 11/12, 2017 at 11:19 Comment(0)
A
0

As an alternative to using 'any' (interface{}), Go 1.19 (Q3 2022) comes with new types in the sync/atomic package that make it easier to use atomic values, such as atomic.Int64 and atomic.Pointer[T].

That would be easier than using atomic.StorePointer.
This comes from issue 50860 "sync/atomic: add typed atomic values".
And CL 381317

Pointer[T] also avoids conversions using unsafe.Pointer at call sites.

Altonaltona answered 16/7, 2022 at 5:53 Comment(0)
C
-2

You cannot do this.

You will have to protect the store/load with a mutex. The internal representation of an interface is not specified by the language and might (is) to large to be handled by package atomic.

Clotheshorse answered 11/12, 2017 at 11:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.