What is atomic package in Go?

The sync/atomic package in Go is used to equip low-level atomic operations, addressing the management of concurrent access to shared variables. These operations encompass addition, subtraction, multiplication, and bitwise operations like AND, OR, and XOR. The distinctive feature of atomic operations lies in their execution as a single step, preventing interference from other threads or goroutinesA goroutine is a lightweight thread managed by the Go runtime. during the ongoing operation. This guarantees the operation’s completion without interruptions, thereby mitigating data races.

Several prevalent atomic operations offered by the sync/atomic package include:

  • AddInt32, AddInt64: Atomically add an integer value to a variable.

  • CompareAndSwapInt32, CompareAndSwapInt64: Execute a compare-and-swap operation on an integer variable atomically.

  • LoadInt32, LoadInt64: Atomically load the value of an integer variable.

  • StoreInt32, StoreInt64: Atomically stores a new value in an integer variable.

  • SwapInt32, SwapInt64: Atomically swap the value of an integer variable with a new value.

Before delving into a coding example, it’s essential to grasp the fundamentals of atomic operations and their significance in concurrent programming.

Significance of atomic operations

In concurrent programming, multiple goroutines access and modify shared variables. Simultaneous attempts by two or more goroutines to modify the same variable can result in unpredictable final values, leading to data races and synchronization complications. This is where atomic operations prove essential.

Atomic operations enable the execution of read, write, or update operations on shared variables in a single, uninterruptible step. This assurance that other goroutines cannot interfere with the ongoing operation helps eliminate data races, ultimately enhancing the performance of concurrent programs.

Having established a foundational comprehension of atomic operations, let’s explore a coding example showcasing the application of Go’s sync/atomic package.

Coding example

We begin with a straightforward code demonstrating the utilization of the sync/atomic package to execute atomic addition on a shared integer variable. In this instance, two goroutines are created, incrementing a shared variable 1000 times. Without the incorporation of atomic operations, this scenario could introduce data races and yield unpredictable outcomes.

package main
import (
"fmt"
"sync"
"sync/atomic"
)
var count int64 // Declare variable to hold the counter value
func main() {
var wg sync.WaitGroup // Declare a WaitGroup to synchronize the goroutines
wg.Add(2) // Add 2 goroutines to the WaitGroup
// Goroutine 1: Increment the counter 1000 times using atomic operations
go func() {
for v := 0; v < 1000; v++ {
atomic.AddInt64(&count, 1) // Atomically increment the counter
}
wg.Done() // Notify WaitGroup that this goroutine is done
}()
// Goroutine 2: Increment the counter 1000 times using atomic operations
go func() {
for v := 0; v < 1000; v++ {
atomic.AddInt64(&count, 1)
}
wg.Done()
}()
wg.Wait() // Wait for all goroutines to finish
fmt.Println("Final counter value:", count)
}

Explanation

Let’s break down the code step by step:

  • Line 9: Here, we declare a global variable count of type int64 (a 64-bit integer), which will serve as the shared counter.

  • Lines 12–13: Here, we initialize a WaitGroup named wg from the sync package to synchronize goroutines. wg.Add(2) indicates that the WaitGroup is expecting two goroutines to complete.

  • Lines 15–20: Here we launch a goroutine using the go keyword. The goroutine increments the count variable by 1, a thousand times, using atomic.AddInt64 to ensure atomicity. wg.Done() signals that the goroutine has completed.

  • Lines 22–27: Similar to Goroutine 1, launches another goroutine to increment the count variable a thousand times atomically.

  • Lines 29–30: The Wait method blocks the main goroutine until the WaitGroup counter becomes zero, i.e., both goroutines have called wg.Done(). Finally, we print the value of the count variable after both goroutines have completed their increments.

This program uses two goroutines to increment a shared counter (count) 2000 times (1000 times each). The sync/atomic package ensures the atomicity of the increment operations and the sync.WaitGroup synchronizes the main goroutine with the two worker goroutines, ensuring the final counter value is printed only after both have completed their tasks.


Free Resources

Copyright ©2025 Educative, Inc. All rights reserved