Go Skills

Mutex

Mutex, what is mutex as per your understanding

In the Go programming language, a mutex (short for “mutual exclusion”) is a type of synchronization mechanism that allows multiple goroutines (lightweight threads of execution) to access shared data concurrently, while protecting against race conditions and data corruption.

A mutex is used to protect a critical section of code, which is a block of code that must be executed by only one goroutine at a time. When a goroutine acquires a mutex, it blocks other goroutines from entering the critical section until the mutex is released. This ensures that only one goroutine can access the shared data at a time, avoiding race conditions and data corruption.

Here is an example of how you might use a mutex to protect a shared resource in Go:

package main

import (
	"fmt"
	"sync"
)

var counter int
var mutex sync.Mutex

func incrementCounter() {
	mutex.Lock()
	defer mutex.Unlock()

	counter++
	fmt.Println("Counter value:", counter)
}

func main() {
	var wg sync.WaitGroup
	wg.Add(5)

	for i := 0; i < 5; i++ {
		go func() {
			defer wg.Done()
			incrementCounter()
		}()
	}

	wg.Wait()
}

In this example, the incrementCounter function uses a mutex to protect the shared counter variable.

The mutex is locked before the critical section of code is executed, and unlocked after the critical section is complete.

This ensures that only one goroutine can access the counter variable at a time, preventing race conditions and data corruption.

Can you write a program, structure 2 go routine, each go routine should increment value simultaneously

Sure! Here is an example program that starts two go routines, each of which increment a shared variable simultaneously:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	var counter int
	wg.Add(2)

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

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

	wg.Wait()
	fmt.Println(counter)
}

This program creates two goroutines, each of which increments the counter variable 1000 times. The sync.WaitGroup is used to wait for both goroutines to finish before printing the final value of counter.

The counter variable is shared between the two goroutines, so it is possible that the two goroutines will increment the variable simultaneously. This can lead to race conditions, where the value of the variable is not what you expect. To prevent race conditions, you can use synchronization techniques like mutexes to ensure that only one goroutine is accessing the shared variable at a time.

To solve race conditions, you can use synchronization techniques like mutexes to ensure that only one goroutine is accessing the shared variable at a time.

Here is an example of how you can use a mutex to solve the race condition in the previous example:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	var counter int
	var mu sync.Mutex
	wg.Add(2)

	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			mu.Lock()
			counter++
			mu.Unlock()
		}
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			mu.Lock()
			counter++
			mu.Unlock()
		}
	}()

	wg.Wait()
	fmt.Println(counter)
}

In this example, the mutex mu is used to ensure that only one goroutine is accessing the counter variable at a time. The mu.Lock() function acquires the mutex lock, and the mu.Unlock() function releases it. This ensures that the two goroutines do not access the counter variable simultaneously, and the race condition is avoided.

Note that using a mutex comes at a cost, as it can add overhead to your program. It is important to use mutexes only when necessary, and to design your program in a way that minimizes the need for synchronization.