Handling concurrent access to shared resources in Golang primarily involves several methods, with mutexes and channels being the most commonly used. I will provide detailed explanations of these two methods along with corresponding code examples.
1. Using Mutex
A mutex is a synchronization primitive designed to prevent conflicts among multiple goroutines when accessing shared resources. Using sync.Mutex to protect shared resources ensures that only one goroutine can access it at a time.
Example:
gopackage main import ( "fmt" "sync" ) var ( counter int lock sync.Mutex ) func increment() { lock.Lock() // Lock before accessing shared resource defer lock.Unlock() // Ensure lock is released using defer counter++ // Safely modify shared resource } func main() { var wg sync.WaitGroup // Create multiple goroutines to simulate concurrent access for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() increment() }() } wg.Wait() // Wait for all goroutines to complete fmt.Println("Counter:", counter) }
In this example, the mutex ensures thread-safe access to counter. Regardless of how many goroutines are launched, the output will consistently be 100.
2. Using Channels
Channels are a fundamental feature in Go, enabling safe data transfer between goroutines. They can also be used to synchronize access to shared resources by controlling data flow.
Example:
gopackage main import ( "fmt" "sync" ) func worker(jobs <-chan int, results chan<- int) { for job := range jobs { results <- job * 2 // Process job and send result to results channel } } func main() { jobs := make(chan int, 100) results := make(chan int, 100) var wg sync.WaitGroup // Start workers to process tasks for w := 0; w < 3; w++ { wg.Add(1) go func() { defer wg.Done() worker(jobs, results) }() } // Send tasks to jobs channel for j := 1; j <= 5; j++ { jobs <- j } close(jobs) wg.Wait() // Wait for all workers to complete close(results) // Close results channel // Collect all results for result := range results { fmt.Println(result) } }
In this example, we establish a jobs channel and a results channel. Worker goroutines receive tasks from the jobs channel and send processed results to the results channel, thereby ensuring safe access to shared resources and data synchronization.
Summary
In Go, concurrent access to shared resources is commonly managed using two mechanisms: mutexes and channels. The selection of which to use depends on the specific context. Mutexes are ideal for safeguarding simple shared data, whereas channels excel in communication and synchronization between goroutines.