A race condition occurs in a concurrent system when two or more processes or threads access shared resources (such as variables, files, or memory) simultaneously, and the final outcome depends on the unpredictable order in which the processes or threads execute. This can lead to unpredictable and erroneous behaviour because the operations are interdependent and not synchronised properly. Example :
counter:=0
go func(){
for i:=0;i<1000;i++{
counter++;
}
}()
go func(){
for i:=0;i<1000;i++{
counter++;
}
}()
In this scenario, both threads might read, increment, and write back the counter simultaneously, causing the final value of counter
to be less than 2000 due to lost updates.
Data race is specific type of race condition which occur when two or more thread or proccess trying to access shared resources and atleast one have write access. Data race can lead to inconsistent and unpredictable results because the order of read and write can not be controlled.
Previous example can be reffered for data race
Mutual exclusion is a principle used in concurrent programming to prevent race conditions by ensuring that only one thread or process can access a critical section of code or a shared resource at a time. This is typically achieved using synchronization mechanisms such as mutexes (locks), semaphores, or monitors.
package main
import (
"sync"
)
var counter int
var mu sync.Mutex
func increment() {
for i := 0; i < 1000; i++ {
mu.Lock() // Acquire the lock
counter++ // Critical section
mu.Unlock() // Release the lock
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
increment()
}()
go func() {
defer wg.Done()
increment()
}()
wg.Wait()
}