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
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 mainimport ("fmt""sync""sync/atomic")var count int64 // Declare variable to hold the counter valuefunc main() {var wg sync.WaitGroup // Declare a WaitGroup to synchronize the goroutineswg.Add(2) // Add 2 goroutines to the WaitGroup// Goroutine 1: Increment the counter 1000 times using atomic operationsgo 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 operationsgo func() {for v := 0; v < 1000; v++ {atomic.AddInt64(&count, 1)}wg.Done()}()wg.Wait() // Wait for all goroutines to finishfmt.Println("Final counter value:", count)}
Explanation
Let’s break down the code step by step:
Line 9: Here, we declare a global variable
countof typeint64(a 64-bit integer), which will serve as the shared counter.Lines 12–13: Here, we initialize a
WaitGroupnamedwgfrom thesyncpackage to synchronize goroutines.wg.Add(2)indicates that theWaitGroupis expecting two goroutines to complete.Lines 15–20: Here we launch a goroutine using the
gokeyword. The goroutine increments thecountvariable by 1, a thousand times, usingatomic.AddInt64to ensure atomicity.wg.Done()signals that the goroutine has completed.Lines 22–27: Similar to Goroutine 1, launches another goroutine to increment the
countvariable a thousand times atomically.Lines 29–30: The
Waitmethod blocks the main goroutine until theWaitGroupcounter becomes zero, i.e., both goroutines have calledwg.Done(). Finally, we print the value of thecountvariable 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