Navigation Menu

Search code, repositories, users, issues, pull requests..., provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is assigning a pointer atomic in go #38667

@SmallSmartMouse

SmallSmartMouse commented Apr 26, 2020

@randall77

randall77 commented Apr 26, 2020

Sorry, something went wrong.

@randall77

SmallSmartMouse commented Apr 29, 2020

@lsytj0413

lsytj0413 commented Apr 29, 2020

@ianlancetaylor

ianlancetaylor commented Apr 30, 2020

@smallnest

No branches or pull requests

@ianlancetaylor

Atomic Operations Provided in The sync/atomic Standard Package

Atomic operations are more primitive than other synchronization techniques. They are lockless and generally implemented directly at hardware level. In fact, they are often used in implementing other synchronization techniques.

Please note, many examples below are not concurrent programs. They are just for demonstration and explanation purposes, to show how to use the atomic functions provided in the sync/atomic standard package.

Overview of Atomic Operations Provided Before Go 1.19-

There is not an AddPointer function for pointers, as Go (safe) pointers don't support arithmetic operations.

Overview of New Atomic Operations Provided Since Go 1.19

Go 1.19 introduced several types, each of which owns a set of atomic operation methods, to achieve the same effects made by the package-level functions listed in the last section.

Among these types, Int32 , Int64 , Uint32 , Uint64 and Uintptr are for integer atomic operations. The methods of the atomic.Int32 type are listed below. The methods of the other four types present in the similar way.

Since Go 1.18, Go has already supported custom generics. And some standard packages started to adopt custom generics since Go 1.19. The sync/atomic package is one of these packages. The Pointer[T any] type introudced in this package by Go 1.19 is a generic type. Its methods are listed below.

Go 1.19 also introduced a Bool type to do boolean atomic operations.

Atomic Operations for Integers

The remaining of this article shows some examples on how to use the atomic operations provided in Go.

If the statement atomic.AddInt32(&n, 1) is replaced with n++ , then the output might be not 1000 .

  • For an unsigned variable v of type T , -v is legal in Go. So we can just pass -v as the second argument of an AddT call.
  • For a positive constant integer c , -c is illegal to be used as the second argument of an AddT call (where T denotes an unsigned integer type). We can used ^T(c-1) as the second argument instead.

This ^T(v-1) trick also works for an unsigned variable v , but ^T(v-1) is less efficient than T(-v) .

In the trick ^T(c-1) , if c is a typed value and its type is exactly T , then the form can shortened as ^(c-1) .

A SwapT function call is like a StoreT function call, but returns the old value.

A CompareAndSwapT function call only applies the store operation when the current value matches the passed old value. The bool return result of the CompareAndSwapT function call indicates whether or not the store operation is applied.

Please note, up to now (Go 1.22), atomic operations for 64-bit words, a.k.a. int64 and uint64 values, require the 64-bit words must be 8-byte aligned in memory. For Go 1.19 introduced atomic method operations, this requirement is always satisfied, either on 32-bit or 64-bit architectures, but this is not true for atomic function operations on 32-bit architectures. Please read memory layout for details.

Atomic Operations for Pointers

Above has mentioned that there are four functions provided in the sync/atomic standard package to do atomic pointer operations, with the help of unsafe pointers.

From the article type-unsafe pointers , we learn that, in Go, values of any pointer type can be explicitly converted to unsafe.Pointer , and vice versa. So values of *unsafe.Pointer type can also be explicitly converted to unsafe.Pointer , and vice versa.

Yes, it is quite verbose to use the pointer atomic functions. In fact, not only are the uses verbose, they are also not protected by Go 1 compatibility guidelines , for these uses require to import the unsafe standard package.

Personally, I think the possibility is small that the legal pointer value atomic operations used in the above example will become illegal later. Even if they become illegal later, the go fix command provided in Go Toolchain should fix them with a later alternative new legal way. But, this is just my opinion, which is not authoritative.

If you do worry about the future legality of the pointer atomic operations used in the above example, you can use the atomic operations introduced in the next section for pointers, though the to be introduced operations are less efficient than the ones introduced in the current section.

On the contrary, the code will be much simpler and cleaner if we use the Go 1.19 introduced generic Pointer type and its methods to do atomic pointer operations, as the following code shows.

More importantly, the implementation using the generic Pointer type is protected by Go 1 compatibility guidelines.

Atomic Operations for Values of Arbitrary Types

The Value type provided in the sync/atomic standard package can be used to atomically load and store values of any type.

Type *Value has several methods: Load , Store , Swap and CompareAndSwap (The latter two are introduced in Go 1.17). The input parameter types of these methods are all interface{} . So any value may be passed to the calls to these methods. But for an addressable Value value v , once the v.Store() (a shorthand of (&v).Store() ) call has ever been called, then the subsequent method calls on value v must also take argument values with the same concrete type as the argument of the first v.Store() call, otherwise, panics will occur. A nil interface argument will also make the v.Store() call panic.

In fact, we can also use the atomic pointer functions explained in the last section to do atomic operations for values of any type, with one more level indirection. Both ways have their respective advantages and disadvantages. Which way should be used depends on the requirements in practice.

Memory Order Guarantee Made by Atomic Operations in Go

Please read Go memory model for details.

The Go 101 project is hosted on Github . Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.

If you would like to learn some Go details and facts every serveral days, please follow Go 101's official Twitter account @zigo_101 .

  • Leanpub store , $19.99+ (You can get this book from this boundle which also contains 3 other books, with the same price) .
  • Amazon Kindle store, (unavailable currently) .
  • Apple Books store , $19.99 .
  • Google Play store , $19.99 .
  • Free ebooks , including pdf, epub and azw3 formats.
  • Color Infection (★★★★★), a physics based original casual puzzle game. 140+ levels.
  • Rectangle Pushers (★★★★★), an original casual puzzle game. Two modes, 104+ levels.
  • Let's Play With Particles , a casual action original game. Three mini games are included.
  • About Go 101 - why this book is written.
  • Acknowledgments
  • An Introduction of Go - why Go is worth learning.
  • The Go Toolchain - how to compile and run Go programs.
  • Introduction of Source Code Elements
  • Keywords and Identifiers
  • Basic Types and Their Value Literals
  • Constants and Variables - also introduces untyped values and type deductions.
  • Common Operators - also introduces more type deduction rules.
  • Function Declarations and Calls
  • Code Packages and Package Imports
  • Expressions, Statements and Simple Statements
  • Basic Control Flows
  • Goroutines, Deferred Function Calls and Panic/Recover
  • Go Type System Overview - a must read to master Go programming.
  • Value Parts - to gain a deeper understanding into Go values.
  • Arrays, Slices and Maps - first-class citizen container types.
  • Functions - function types and values, including variadic functions.
  • Channels - the Go way to do concurrency synchronizations.
  • Interfaces - value boxes used to do reflection and polymorphism.
  • Type Embedding - type extension in the Go way.
  • Type-Unsafe Pointers
  • Generics - use and read composite types
  • Reflections - the reflect standard package.
  • Line Break Rules
  • More About Deferred Function Calls
  • Some Panic/Recover Use Cases
  • Explain Panic/Recover Mechanism in Detail - also explains exiting phases of function calls.
  • Code Blocks and Identifier Scopes
  • Expression Evaluation Orders
  • Value Copy Costs in Go
  • Bounds Check Elimination
  • Concurrency Synchronization Overview
  • Channel Use Cases
  • How to Gracefully Close Channels
  • Other Concurrency Synchronization Techniques - the sync standard package.
  • Atomic Operations - the sync/atomic standard package.
  • Memory Order Guarantees in Go
  • Common Concurrent Programming Mistakes
  • Memory Blocks
  • Memory Layouts
  • Memory Leaking Scenarios
  • Some Simple Summaries
  • Value Conversion, Assignment and Comparison Rules
  • Syntax/Semantics Exceptions
  • Go Details 101
  • Go Tips 101
  • More Go Related Topics

Atomic Operations in Golang – atomic package

Atomic operations are those which are implemented at the hardware level. Go has the atomic package which helps to achieve synchronization when doing concurrency. In this post, we will see what the atomic package has to offer.

What is an atomic operation?

If we do an operation like increment or decrement using channels on a single shared variable, the goroutines will not be synchronized and will produce erroneous output. The atomic operations, on the other hand, are implemented at the hardware level. That means when we create a shared atomic variable and use multiple goroutines to update its value it will be updated correctly.

Importing Golang atomic package

To use the atomic functions we need to import the sync/atomic package.

Atomic functions in Golang

The package contains load, store and the addition operation for the int32, int 64, uint32, uint64, etc. Since only ints are such primitive that can be correctly synchronized using atomics.

Let’s see an example of what can happen if we don’t use atomic.

Go Non Atomic

As can be seen each time the program is run it will produce the wrong output. It happens due to the fact the goroutines accessing and changing the value is not synchronized. So, the changed values are arbitrary and will result in the wrong number of operations.

Now, we convert the code above to synchronized code using atomic.

Now, each time we run it, it will produce the correct output. Since the atomic operations are synchronized it will return the correct output no matter what.

Go Atomic Operation

Use of atomic operations in Golang

Atomic operations are used when we need to have a shared variable between different goroutines which will be updated by them. If the updating operation is not synchronized then it will create a problem that we saw.

Atomic operations solve that problem by synchronizing access to the shared variable and making the output correct.

This package is not in the latest version of its module.

Documentation ¶

Package atomic provides low-level atomic memory primitives useful for implementing synchronization algorithms.

These functions require great care to be used correctly. Except for special, low-level applications, synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate by sharing memory.

The swap operation, implemented by the SwapT functions, is the atomic equivalent of:

The compare-and-swap operation, implemented by the CompareAndSwapT functions, is the atomic equivalent of:

The add operation, implemented by the AddT functions, is the atomic equivalent of:

The load and store operations, implemented by the LoadT and StoreT functions, are the atomic equivalents of "return *addr" and "*addr = val".

In the terminology of the Go memory model, if the effect of an atomic operation A is observed by atomic operation B, then A “synchronizes before” B. Additionally, all the atomic operations executed in a program behave as though executed in some sequentially consistent order. This definition provides the same semantics as C++'s sequentially consistent atomics and Java's volatile variables.

  • func AddInt32(addr *int32, delta int32) (new int32)
  • func AddInt64(addr *int64, delta int64) (new int64)
  • func AddUint32(addr *uint32, delta uint32) (new uint32)
  • func AddUint64(addr *uint64, delta uint64) (new uint64)
  • func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
  • func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
  • func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
  • func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
  • func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
  • func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
  • func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)
  • func LoadInt32(addr *int32) (val int32)
  • func LoadInt64(addr *int64) (val int64)
  • func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
  • func LoadUint32(addr *uint32) (val uint32)
  • func LoadUint64(addr *uint64) (val uint64)
  • func LoadUintptr(addr *uintptr) (val uintptr)
  • func StoreInt32(addr *int32, val int32)
  • func StoreInt64(addr *int64, val int64)
  • func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
  • func StoreUint32(addr *uint32, val uint32)
  • func StoreUint64(addr *uint64, val uint64)
  • func StoreUintptr(addr *uintptr, val uintptr)
  • func SwapInt32(addr *int32, new int32) (old int32)
  • func SwapInt64(addr *int64, new int64) (old int64)
  • func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
  • func SwapUint32(addr *uint32, new uint32) (old uint32)
  • func SwapUint64(addr *uint64, new uint64) (old uint64)
  • func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
  • func (x *Bool) CompareAndSwap(old, new bool) (swapped bool)
  • func (x *Bool) Load() bool
  • func (x *Bool) Store(val bool)
  • func (x *Bool) Swap(new bool) (old bool)
  • func (x *Int32) Add(delta int32) (new int32)
  • func (x *Int32) CompareAndSwap(old, new int32) (swapped bool)
  • func (x *Int32) Load() int32
  • func (x *Int32) Store(val int32)
  • func (x *Int32) Swap(new int32) (old int32)
  • func (x *Int64) Add(delta int64) (new int64)
  • func (x *Int64) CompareAndSwap(old, new int64) (swapped bool)
  • func (x *Int64) Load() int64
  • func (x *Int64) Store(val int64)
  • func (x *Int64) Swap(new int64) (old int64)
  • type Pointer
  • func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool)
  • func (x *Pointer[T]) Load() *T
  • func (x *Pointer[T]) Store(val *T)
  • func (x *Pointer[T]) Swap(new *T) (old *T)
  • type Uint32
  • func (x *Uint32) Add(delta uint32) (new uint32)
  • func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool)
  • func (x *Uint32) Load() uint32
  • func (x *Uint32) Store(val uint32)
  • func (x *Uint32) Swap(new uint32) (old uint32)
  • type Uint64
  • func (x *Uint64) Add(delta uint64) (new uint64)
  • func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool)
  • func (x *Uint64) Load() uint64
  • func (x *Uint64) Store(val uint64)
  • func (x *Uint64) Swap(new uint64) (old uint64)
  • type Uintptr
  • func (x *Uintptr) Add(delta uintptr) (new uintptr)
  • func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool)
  • func (x *Uintptr) Load() uintptr
  • func (x *Uintptr) Store(val uintptr)
  • func (x *Uintptr) Swap(new uintptr) (old uintptr)
  • func (v *Value) CompareAndSwap(old, new any) (swapped bool)
  • func (v *Value) Load() (val any)
  • func (v *Value) Store(val any)
  • func (v *Value) Swap(new any) (old any)
  • Value (Config)
  • Value (ReadMostly)

Constants ¶

This section is empty.

Variables ¶

Functions ¶, func addint32 ¶.

AddInt32 atomically adds delta to *addr and returns the new value. Consider using the more ergonomic and less error-prone Int32.Add instead.

func AddInt64 ¶

AddInt64 atomically adds delta to *addr and returns the new value. Consider using the more ergonomic and less error-prone Int64.Add instead (particularly if you target 32-bit platforms; see the bugs section).

func AddUint32 ¶

AddUint32 atomically adds delta to *addr and returns the new value. To subtract a signed positive constant value c from x, do AddUint32(&x, ^uint32(c-1)). In particular, to decrement x, do AddUint32(&x, ^uint32(0)). Consider using the more ergonomic and less error-prone Uint32.Add instead.

func AddUint64 ¶

AddUint64 atomically adds delta to *addr and returns the new value. To subtract a signed positive constant value c from x, do AddUint64(&x, ^uint64(c-1)). In particular, to decrement x, do AddUint64(&x, ^uint64(0)). Consider using the more ergonomic and less error-prone Uint64.Add instead (particularly if you target 32-bit platforms; see the bugs section).

func AddUintptr ¶

AddUintptr atomically adds delta to *addr and returns the new value. Consider using the more ergonomic and less error-prone Uintptr.Add instead.

func CompareAndSwapInt32 ¶

CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value. Consider using the more ergonomic and less error-prone Int32.CompareAndSwap instead.

func CompareAndSwapInt64 ¶

CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value. Consider using the more ergonomic and less error-prone Int64.CompareAndSwap instead (particularly if you target 32-bit platforms; see the bugs section).

func CompareAndSwapPointer ¶

CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value. Consider using the more ergonomic and less error-prone Pointer.CompareAndSwap instead.

func CompareAndSwapUint32 ¶

CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value. Consider using the more ergonomic and less error-prone Uint32.CompareAndSwap instead.

func CompareAndSwapUint64 ¶

CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value. Consider using the more ergonomic and less error-prone Uint64.CompareAndSwap instead (particularly if you target 32-bit platforms; see the bugs section).

func CompareAndSwapUintptr ¶

CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value. Consider using the more ergonomic and less error-prone Uintptr.CompareAndSwap instead.

func LoadInt32 ¶

LoadInt32 atomically loads *addr. Consider using the more ergonomic and less error-prone Int32.Load instead.

func LoadInt64 ¶

LoadInt64 atomically loads *addr. Consider using the more ergonomic and less error-prone Int64.Load instead (particularly if you target 32-bit platforms; see the bugs section).

func LoadPointer ¶

LoadPointer atomically loads *addr. Consider using the more ergonomic and less error-prone Pointer.Load instead.

func LoadUint32 ¶

LoadUint32 atomically loads *addr. Consider using the more ergonomic and less error-prone Uint32.Load instead.

func LoadUint64 ¶

LoadUint64 atomically loads *addr. Consider using the more ergonomic and less error-prone Uint64.Load instead (particularly if you target 32-bit platforms; see the bugs section).

func LoadUintptr ¶

LoadUintptr atomically loads *addr. Consider using the more ergonomic and less error-prone Uintptr.Load instead.

func StoreInt32 ¶

StoreInt32 atomically stores val into *addr. Consider using the more ergonomic and less error-prone Int32.Store instead.

func StoreInt64 ¶

StoreInt64 atomically stores val into *addr. Consider using the more ergonomic and less error-prone Int64.Store instead (particularly if you target 32-bit platforms; see the bugs section).

func StorePointer ¶

StorePointer atomically stores val into *addr. Consider using the more ergonomic and less error-prone Pointer.Store instead.

func StoreUint32 ¶

StoreUint32 atomically stores val into *addr. Consider using the more ergonomic and less error-prone Uint32.Store instead.

func StoreUint64 ¶

StoreUint64 atomically stores val into *addr. Consider using the more ergonomic and less error-prone Uint64.Store instead (particularly if you target 32-bit platforms; see the bugs section).

func StoreUintptr ¶

StoreUintptr atomically stores val into *addr. Consider using the more ergonomic and less error-prone Uintptr.Store instead.

func SwapInt32 ¶ added in go1.2

SwapInt32 atomically stores new into *addr and returns the previous *addr value. Consider using the more ergonomic and less error-prone Int32.Swap instead.

func SwapInt64 ¶ added in go1.2

SwapInt64 atomically stores new into *addr and returns the previous *addr value. Consider using the more ergonomic and less error-prone Int64.Swap instead (particularly if you target 32-bit platforms; see the bugs section).

func SwapPointer ¶ added in go1.2

SwapPointer atomically stores new into *addr and returns the previous *addr value. Consider using the more ergonomic and less error-prone Pointer.Swap instead.

func SwapUint32 ¶ added in go1.2

SwapUint32 atomically stores new into *addr and returns the previous *addr value. Consider using the more ergonomic and less error-prone Uint32.Swap instead.

func SwapUint64 ¶ added in go1.2

SwapUint64 atomically stores new into *addr and returns the previous *addr value. Consider using the more ergonomic and less error-prone Uint64.Swap instead (particularly if you target 32-bit platforms; see the bugs section).

func SwapUintptr ¶ added in go1.2

SwapUintptr atomically stores new into *addr and returns the previous *addr value. Consider using the more ergonomic and less error-prone Uintptr.Swap instead.

type Bool ¶ added in go1.19

A Bool is an atomic boolean value. The zero value is false.

func (*Bool) CompareAndSwap ¶ added in go1.19

CompareAndSwap executes the compare-and-swap operation for the boolean value x.

func (*Bool) Load ¶ added in go1.19

Load atomically loads and returns the value stored in x.

func (*Bool) Store ¶ added in go1.19

Store atomically stores val into x.

func (*Bool) Swap ¶ added in go1.19

Swap atomically stores new into x and returns the previous value.

type Int32 ¶ added in go1.19

An Int32 is an atomic int32. The zero value is zero.

func (*Int32) Add ¶ added in go1.19

Add atomically adds delta to x and returns the new value.

func (*Int32) CompareAndSwap ¶ added in go1.19

CompareAndSwap executes the compare-and-swap operation for x.

func (*Int32) Load ¶ added in go1.19

Func (*int32) store ¶ added in go1.19, func (*int32) swap ¶ added in go1.19, type int64 ¶ added in go1.19.

An Int64 is an atomic int64. The zero value is zero.

func (*Int64) Add ¶ added in go1.19

Func (*int64) compareandswap ¶ added in go1.19, func (*int64) load ¶ added in go1.19, func (*int64) store ¶ added in go1.19, func (*int64) swap ¶ added in go1.19, type pointer ¶ added in go1.19.

A Pointer is an atomic pointer of type *T. The zero value is a nil *T.

func (*Pointer[T]) CompareAndSwap ¶ added in go1.19

Func (*pointer[t]) load ¶ added in go1.19, func (*pointer[t]) store ¶ added in go1.19, func (*pointer[t]) swap ¶ added in go1.19, type uint32 ¶ added in go1.19.

A Uint32 is an atomic uint32. The zero value is zero.

func (*Uint32) Add ¶ added in go1.19

Func (*uint32) compareandswap ¶ added in go1.19, func (*uint32) load ¶ added in go1.19, func (*uint32) store ¶ added in go1.19, func (*uint32) swap ¶ added in go1.19, type uint64 ¶ added in go1.19.

A Uint64 is an atomic uint64. The zero value is zero.

func (*Uint64) Add ¶ added in go1.19

Func (*uint64) compareandswap ¶ added in go1.19, func (*uint64) load ¶ added in go1.19, func (*uint64) store ¶ added in go1.19, func (*uint64) swap ¶ added in go1.19, type uintptr ¶ added in go1.19.

A Uintptr is an atomic uintptr. The zero value is zero.

func (*Uintptr) Add ¶ added in go1.19

Func (*uintptr) compareandswap ¶ added in go1.19, func (*uintptr) load ¶ added in go1.19, func (*uintptr) store ¶ added in go1.19, func (*uintptr) swap ¶ added in go1.19, type value ¶ added in go1.4.

A Value provides an atomic load and store of a consistently typed value. The zero value for a Value returns nil from Load. Once Store has been called, a Value must not be copied.

A Value must not be copied after first use.

The following example shows how to use Value for periodic program config updates and propagation of the changes to worker goroutines.

The following example shows how to maintain a scalable frequently read, but infrequently updated data structure using copy-on-write idiom.

func (*Value) CompareAndSwap ¶ added in go1.17

CompareAndSwap executes the compare-and-swap operation for the Value.

All calls to CompareAndSwap for a given Value must use values of the same concrete type. CompareAndSwap of an inconsistent type panics, as does CompareAndSwap(old, nil).

func (*Value) Load ¶ added in go1.4

Load returns the value set by the most recent Store. It returns nil if there has been no call to Store for this Value.

func (*Value) Store ¶ added in go1.4

Store sets the value of the Value v to val. All calls to Store for a given Value must use values of the same concrete type. Store of an inconsistent type panics, as does Store(nil).

func (*Value) Swap ¶ added in go1.17

Swap stores new into Value and returns the previous value. It returns nil if the Value is empty.

All calls to Swap for a given Value must use values of the same concrete type. Swap of an inconsistent type panics, as does Swap(nil).

On 386, the 64-bit functions use instructions unavailable before the Pentium MMX.

On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core.

On ARM, 386, and 32-bit MIPS, it is the caller's responsibility to arrange for 64-bit alignment of 64-bit words accessed atomically via the primitive atomic functions (types Int64 and Uint64 are automatically aligned). The first word in an allocated struct, array, or slice; in a global variable; or in a local variable (because the subject of all atomic operations will escape to the heap) can be relied upon to be 64-bit aligned.

Source Files ¶

Keyboard shortcuts.

Golang Libraries, Apps, Golang Jobs and Go Tutorials

Golang News, Tutorials, Go Libraries and Golang Jobs

  • Golang Jobs / Go Developer Jobs
  • Go/JS Full Stack Development

How to use Atomic Pointers in Golang 1.19

“Atomic” in computer programming refers to performing operations one at a time. Objective-C has atomic properties. It ensures a safe reading and writing to a property from different threads. In Objective-C, it is used with immutable types. This is because immutable types are really “recreated” to change it. In other words, changing an immutable type in your code will not cause the compiler to throw an error. However, it’ll instantiate a new object when you do so. A prime example is Go’s append function, it makes a new array for each invocation. In Obj-C, atomic properties will ensure operations are performed one after another to prevent threads from accessing a memory address simultaneously. Since Go is multithreaded, it supports atomic operations as well. Golang 1.19 introduces new atomic types. My favorite addition is  atomic.Pointer  , it provides a sleek alternative to  atomic.Value  . It’s also a great showcase of how generics enhance the developer experience.

The Go 1.19 atomic.Pointer

atomic.Pointer  is a generic type. Unlike  Value  , it does not require asserting your stored value to access it. Here is a code block that defines and stores a pointer :

I instantiate variable  p as a struct literal. I then proceed to store the pointer of the variable s in p , s represents a server connection. Voila, we’ve passed the first step toward atomicity. By storing the variable as an atomic value, we’ll ensure that there is no simultaneous access to the memory address. For example, maps will cause a program to panic if it is read and written simultaneously. As are atomic operations, locks are a great way to prevent these panics.

Golang Atomic Pointer use cases

is pointer assignment atomic in golang

Golang Libraries, Apps, Golang Jobs and Go Tutorials 2024 . Powered by WordPress

Ensuring Concurrency Safety with Atomic Operations in Golang

Table of contents.

In many backend services, configuration files or dictionary data need to be loaded dynamically. So when accessing these configurations or dictionaries, it is necessary to add locks to these data to ensure the security of concurrent reads and writes. Normally, read and write locks are required. Here’s an example of a read/write lock.

Read/Write Locks to Load Data

Using read/write locks ensures that access to data does not result in a race to state.

Dynamic data replacement using atomic operations

One characteristic of this type of business requirement is that reads are very frequent, but updates to the data will be relatively infrequent. We can replace the read and write locks with the following method.

Using atomic operations ensures that when concurrent reads and writes are performed, the new map is not acquired by the previous read operation when the data is updated, thus ensuring concurrent security.

Performance Test

Here is a performance test where ConfigV2 is using atomic operations to replace the data of map.

The difference between the two is 40 times, and the results are as follows:

  • In some kinds of business where there are many reads and few writes, atomic operations can be used instead of read/write locks to ensure concurrency security.
  • The reason for the higher performance of atomic operations may be: read-write locks require one more atomic operation to be added. (To be verified)

Go by Example : Atomic Counters

Next example: Mutexes .

by Mark McGranaghan and Eli Bendersky | source | license

Package atomic

Package atomic provides low-level atomic memory primitives useful for implementing synchronization algorithms.

These functions require great care to be used correctly. Except for special, low-level applications, synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate by sharing memory.

The swap operation, implemented by the SwapT functions, is the atomic equivalent of:

The compare-and-swap operation, implemented by the CompareAndSwapT functions, is the atomic equivalent of:

The add operation, implemented by the AddT functions, is the atomic equivalent of:

The load and store operations, implemented by the LoadT and StoreT functions, are the atomic equivalents of "return *addr" and "*addr = val".

Package files

doc.go value.go

func AddInt32 ¶

AddInt32 atomically adds delta to *addr and returns the new value.

func AddInt64 ¶

AddInt64 atomically adds delta to *addr and returns the new value.

func AddUint32 ¶

AddUint32 atomically adds delta to *addr and returns the new value. To subtract a signed positive constant value c from x, do AddUint32(&x, ^uint32(c-1)). In particular, to decrement x, do AddUint32(&x, ^uint32(0)).

func AddUint64 ¶

AddUint64 atomically adds delta to *addr and returns the new value. To subtract a signed positive constant value c from x, do AddUint64(&x, ^uint64(c-1)). In particular, to decrement x, do AddUint64(&x, ^uint64(0)).

func AddUintptr ¶

AddUintptr atomically adds delta to *addr and returns the new value.

func CompareAndSwapInt32 ¶

CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.

func CompareAndSwapInt64 ¶

CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.

func CompareAndSwapPointer ¶

CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.

func CompareAndSwapUint32 ¶

CompareAndSwapUint32 executes the compare-and-swap operation for a uint32 value.

func CompareAndSwapUint64 ¶

CompareAndSwapUint64 executes the compare-and-swap operation for a uint64 value.

func CompareAndSwapUintptr ¶

CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.

func LoadInt32 ¶

LoadInt32 atomically loads *addr.

func LoadInt64 ¶

LoadInt64 atomically loads *addr.

func LoadPointer ¶

LoadPointer atomically loads *addr.

func LoadUint32 ¶

LoadUint32 atomically loads *addr.

func LoadUint64 ¶

LoadUint64 atomically loads *addr.

func LoadUintptr ¶

LoadUintptr atomically loads *addr.

func StoreInt32 ¶

StoreInt32 atomically stores val into *addr.

func StoreInt64 ¶

StoreInt64 atomically stores val into *addr.

func StorePointer ¶

StorePointer atomically stores val into *addr.

func StoreUint32 ¶

StoreUint32 atomically stores val into *addr.

func StoreUint64 ¶

StoreUint64 atomically stores val into *addr.

func StoreUintptr ¶

StoreUintptr atomically stores val into *addr.

func SwapInt32 ¶ 1.2

SwapInt32 atomically stores new into *addr and returns the previous *addr value.

func SwapInt64 ¶ 1.2

SwapInt64 atomically stores new into *addr and returns the previous *addr value.

func SwapPointer ¶ 1.2

SwapPointer atomically stores new into *addr and returns the previous *addr value.

func SwapUint32 ¶ 1.2

SwapUint32 atomically stores new into *addr and returns the previous *addr value.

func SwapUint64 ¶ 1.2

SwapUint64 atomically stores new into *addr and returns the previous *addr value.

func SwapUintptr ¶ 1.2

SwapUintptr atomically stores new into *addr and returns the previous *addr value.

type Value ¶ 1.4

A Value provides an atomic load and store of a consistently typed value. The zero value for a Value returns nil from Load. Once Store has been called, a Value must not be copied.

A Value must not be copied after first use.

The following example shows how to use Value for periodic program config updates and propagation of the changes to worker goroutines.

The following example shows how to maintain a scalable frequently read, but infrequently updated data structure using copy-on-write idiom.

func (*Value) CompareAndSwap ¶ 1.17

CompareAndSwap executes the compare-and-swap operation for the Value.

All calls to CompareAndSwap for a given Value must use values of the same concrete type. CompareAndSwap of an inconsistent type panics, as does CompareAndSwap(old, nil).

func (*Value) Load ¶ 1.4

Load returns the value set by the most recent Store. It returns nil if there has been no call to Store for this Value.

func (*Value) Store ¶ 1.4

Store sets the value of the Value to x. All calls to Store for a given Value must use values of the same concrete type. Store of an inconsistent type panics, as does Store(nil).

func (*Value) Swap ¶ 1.17

Swap stores new into Value and returns the previous value. It returns nil if the Value is empty.

All calls to Swap for a given Value must use values of the same concrete type. Swap of an inconsistent type panics, as does Swap(nil).

On 386, the 64-bit functions use instructions unavailable before the Pentium MMX.

On non-Linux ARM, the 64-bit functions use instructions unavailable before the ARMv6k core.

On ARM, 386, and 32-bit MIPS, it is the caller's responsibility to arrange for 64-bit alignment of 64-bit words accessed atomically. The first word in a variable or in an allocated struct, array, or slice can be relied upon to be 64-bit aligned.

go-language.org

Documentation License: Creative Commons Attribution 3.0 License | Code License: BSD-3-Clause

  • Data Types in Go
  • Go Keywords
  • Go Control Flow
  • Go Functions
  • GoLang Structures
  • GoLang Arrays
  • GoLang Strings
  • GoLang Pointers
  • GoLang Interface
  • GoLang Concurrency

atomic.StorePointer() Function in Golang With Examples

  • atomic.StoreInt32() Function in Golang With Examples
  • atomic.StoreInt64() Function in Golang With Examples
  • atomic.StoreUintptr() Function in Golang With Examples
  • atomic.Store() Function in Golang With Examples
  • atomic.LoadPointer() Function in Golang With Examples
  • atomic.StoreUint64() Function in Golang With Examples
  • atomic.SwapPointer() Function in Golang With Examples
  • atomic.StoreUint32() Function in Golang With Examples
  • atomic.SwapInt64() Function in Golang With Examples
  • atomic.SwapUintptr() Function in Golang With Examples
  • atomic.SwapInt32() Function in Golang With Examples
  • atomic.SwapUint64() Function in Golang With Examples
  • atomic.SwapUint32() Function in Golang With Examples
  • atomic.LoadInt64() Function in Golang With Examples
  • atomic.LoadInt32() Function in Golang With Examples
  • atomic.LoadUintptr() Function in Golang With Examples
  • atomic.LoadUint64() Function in Golang With Examples
  • atomic.LoadUint32() Function in Golang With Examples
  • atomic.Load() Function in Golang With Examples

In Go language, atomic packages supply lower-level atomic memory that is helpful is implementing synchronization algorithms. The StorePointer() function in Go language is used to atomically store val into *addr . This function is defined under the atomic package. Here, you need to import the “sync/atomic” package in order to use these functions.

Here, addr indicates address.

Note: (*unsafe.Pointer) is the pointer to a unsafe.Pointer value. And unsafe.Pointer type is helpful in enabling transitions between arbitrary types and builtin uintptr type. Moreover, unsafe is a package that is helpful in type safety of Go programs.

Return Value: It stores the val into *addr and then can be returned when required.

Here, the value unsafe.Pointer is stored in *addr that’s why above code returns the stated output.

Here, the stated unsafe.Pointer val is stored and the address of the stored val is returned here. Moreover, the address can be different at different run times.

author

Please Login to comment...

Similar reads.

  • GoLang-atomic
  • Go Language

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

IMAGES

  1. Playing with Pointers in Golang

    is pointer assignment atomic in golang

  2. How to use Atomic Pointers in Golang 1.19

    is pointer assignment atomic in golang

  3. GoLang Tutorial

    is pointer assignment atomic in golang

  4. GoLang Tutorial

    is pointer assignment atomic in golang

  5. Golang Atomic

    is pointer assignment atomic in golang

  6. Pointers in Golang

    is pointer assignment atomic in golang

VIDEO

  1. Pointers In Go Programming Language

  2. BARC Assignment Atomic & Molecular Physics @physicsgalaxy1537

  3. Why Map Pointer Values In Golang Will Shoot You In The Foot

  4. BCHCT 131 solved assignment 2024 // BCHCT 131 solved Assignment 2024-25 // #bchct131 #bchct131_ignou

  5. Atomic

  6. Golang backend assignment Demo

COMMENTS

  1. Is assigning a pointer atomic in Go?

    The latter property is called visibility. The answer to the former, as of right now is yes, assigning (loading/storing) a pointer is atomic in Golang, this lies in the updated Go memory model. Otherwise, a read r of a memory location x that is not larger than a machine word must observe some write w such that r does not happen before w and ...

  2. Is variable assignment atomic in go?

    The APIs in the sync/atomic package are collectively "atomic operations" that can be used to synchronize the execution of different goroutines. If the effect of an atomic operation A is observed by atomic operation B, then A is synchronized before B. All the atomic operations executed in a program behave as though executed in some ...

  3. Atomic Pointers in Go 1.19

    In Obj-C, atomic properties will ensure operations are performed one after another, to prevent threads from accessing a memory address at the same time. Since Go is multithreaded, it supports atomic operations as well. Go 1.19 introduces new atomic types. My favorite addition is atomic.Pointer , it provides a sleek alternative to atomic.Value .

  4. Is assigning a pointer atomic in go · Issue #38667 · golang/go

    More generally, pointer assignment is atomic, but you need more than that to make an example like yours work. ... golang locked and limited conversation to collaborators Apr 30, 2021. gopherbot added the FrozenDueToAge label Apr 30, 2021.

  5. The Go 1.19 Atomic Wrappers and why to use them

    The first sentence on their readme: Simple wrappers for primitive types to enforce atomic access. Fast-forward to Go 1.19 and beyond and a new set of sync/atomic types have been added to the ...

  6. Atomic Operations Provided in The sync/atomic Standard Package

    Above has mentioned that there are four functions provided in the sync/atomic standard package to do atomic pointer operations, with the help of unsafe pointers. From the article type-unsafe pointers, we learn that, in Go, values of any pointer type can be explicitly converted to unsafe.Pointer, and vice versa.So values of *unsafe.Pointer type can also be explicitly converted to unsafe.Pointer ...

  7. Atomic Operations in Go: Lockless techniques for managing state and

    Go provides a package named sync/atomic that includes a set of functions for performing atomic operations on primitive data types, such as integers and pointers. Some of the commonly used atomic ...

  8. Atomic Operations in Golang

    The atomic operations, on the other hand, are implemented at the hardware level. That means when we create a shared atomic variable and use multiple goroutines to update its value it will be updated correctly. Importing Golang atomic package. To use the atomic functions we need to import the sync/atomic package.

  9. atomic package

    The following example shows how to maintain a scalable frequently read, but infrequently updated data structure using copy-on-write idiom. package main import ( "sync" "sync/atomic" ) func main() { type Map map[string]string var m atomic.Value m.Store(make(Map)) var mu sync.Mutex // used only by writers // read function can be used to read the data without further synchronization read := func ...

  10. Atomic pointer in Golang 1.19 and dependency injection

    Prior to Golang 1.19, the typical solution was using the sync.Mutex. It works, but complicated. Atomic pointer. Golang 1.18 introduced generics. Its only a possibility, because Golang keeps the backward compatibility of the standard library. Introducing a new function or struct with generics is possible, like sync/atomic.Pointer, see the ...

  11. Is assigning a map atomic in go

    Hi, @SmallSmartMouse, No, map assignment is not atomic. Also, your reassignment of the global data map with the temp one you created is not atomic. If your idea is to initialize a map and then store it into a global variable where it will be considered read-only, you can do that with the sync/atomic package and some pointer hackery: https ...

  12. How to use Atomic Pointers in Golang 1.19

    In Obj-C, atomic properties will ensure operations are performed one after another to prevent threads from accessing a memory address simultaneously. Since Go is multithreaded, it supports atomic operations as well. Golang 1.19 introduces new atomic types. My favorite addition is atomic.Pointer , it provides a sleek alternative to atomic.Value ...

  13. Ensuring Concurrency Safety with Atomic Operations in Golang

    In some kinds of business where there are many reads and few writes, atomic operations can be used instead of read/write locks to ensure concurrency security. The reason for the higher performance of atomic operations may be: read-write locks require one more atomic operation to be added. (To be verified) golang.

  14. Go by Example: Atomic Counters

    We expect to get exactly 50,000 operations. Had we used a non-atomic integer and incremented it with ops++, we'd likely get a different number, changing between runs, because the goroutines would interfere with each other.Moreover, we'd get data race failures when running with the -race flag. $ go run atomic-counters.go ops: 50000 Next we'll look at mutexes, another tool for managing state.

  15. Pointers in Golang

    Pointers in Go programming language or Golang is a variable that is used to store the memory address of another variable. Pointers in Golang is also termed as the special variables. The variables are used to store some data at a particular memory address in the system. The memory address is always found in hexadecimal format (starting with 0x ...

  16. Atomic Variable in Golang

    Last Updated : 21 Apr, 2020. In Go language, Atomic Variables are utilized in order to control state. Here, the "sync/atomic" package must be used to use these variables. Moreover, it also prevents race conditions which allows two or more Goroutines to access identical sources. The Atomic counters are available for several goroutines.

  17. atomic

    Package atomic provides low-level atomic memory primitives useful for implementing synchronization algorithms. These functions require great care to be used correctly. Except for special, low-level applications, synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate ...

  18. atomic.StorePointer() Function in Golang With Examples

    The StorePointer () function in Go language is used to atomically store val into *addr. This function is defined under the atomic package. Here, you need to import the "sync/atomic" package in order to use these functions. Syntax: Here, addr indicates address. Note: (*unsafe.Pointer) is the pointer to a unsafe.Pointer value.

  19. How to use Load and Store of atomic in golang

    Golang: when there's only one writer change the value using atomic.StoreInt32, is it necessary to use atomic.LoadInt32 in the multiple readers? 1 golang sync/atomic package?

  20. Golang: Assigning a value to struct member that is a pointer

    Why is it an error? Because a pointer only points. It doesn't create anything to point AT. You need to do that. How to set it to false? This all depends on WHY you made it a pointer. Is every copy of this supposed to point to the same bool? Then it should be allocated some space in a creation function.