Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to atomic store & load an interface in golang?

Tags:

atomic

go

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

like image 676
HongyanShen Avatar asked Dec 11 '17 10:12

HongyanShen


2 Answers

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
                }
        }()
}
like image 142
Arman Ordookhani Avatar answered Sep 29 '22 06:09

Arman Ordookhani


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.

like image 32
dev.bmax Avatar answered Sep 29 '22 08:09

dev.bmax