Skip to content

Latest commit

 

History

History

02_atomic

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

⚡ Atomic Operations in Go

💡 What is an Atomic Operation?

An atomic operation is a low-level, indivisible operation that is guaranteed to execute without interruption. Atomic operations ensure that a value is read and written in a single, uninterrupted operation, which is crucial when dealing with shared variables in concurrent programming. This prevents race conditions and ensures the integrity of data.

📝 Types of Atomic Operations in Go

Go provides the sync/atomic package to perform atomic operations on variables. The most common types of atomic operations include:

  1. atomic.AddInt32, atomic.AddInt64: Atomically adds a value to an integer.
  2. atomic.CompareAndSwapInt32, atomic.CompareAndSwapInt64: Atomically compares and swaps a value.
  3. atomic.LoadInt32, atomic.LoadInt64: Atomically loads a value.
  4. atomic.StoreInt32, atomic.StoreInt64: Atomically stores a value.

✅ sync/atomic Operations

1. Creating Atomic Operations

In Go, atomic operations are typically used on integer types (e.g., int32, int64) and pointers. These types ensure that operations are performed atomically and without race conditions.

import "sync/atomic"

2. Atomic Operations on Integer Types

Here are some examples of common atomic operations:

Atomic Add

atomic.AddInt32(&counter, 1) // Atomically adds 1 to the counter

Atomic Compare and Swap (CAS)

success := atomic.CompareAndSwapInt32(&counter, oldValue, newValue)

Atomic Load

value := atomic.LoadInt32(&counter) // Atomically loads the value of the counter

Atomic Store

atomic.StoreInt32(&counter, 100) // Atomically sets the counter to 100

3. Example with Atomic Operations

package main

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

var counter int32

func increment() {
	atomic.AddInt32(&counter, 1) // Atomically increment counter
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			increment()
		}()
	}

	wg.Wait()
	fmt.Println("Final counter:", counter) // Output: Final counter: 1000
}

🔑 Key Concepts with Atomic Operations

  • Atomicity: Atomic operations guarantee that a value is modified in one indivisible operation. This ensures that the value is either fully updated or not updated at all, without interference from other goroutines.
  • Compare and Swap (CAS): This is a common atomic operation where you compare the current value of a variable to an expected value, and if they match, you swap it with a new value. This operation is widely used for implementing lock-free data structures and algorithms.

📚 Best Practices

  • Use atomic operations for simple types: Use atomic operations on int32, int64, and pointers to avoid the overhead of locks, especially when you need to ensure that the value is updated atomically.
  • Avoid locking when using atomic operations: If the problem can be solved with atomic operations, prefer them over locks to reduce contention and improve performance.
  • Use sync/atomic with caution: Atomic operations can be tricky to use correctly, especially in complex scenarios. Ensure that the operation you're performing is genuinely atomic and that the state you're managing can be updated in a thread-safe way.