Correctly Using sync.Cond for Conditional Waiting
While exploring the functionality of sync.Cond, it became evident that a race condition could arise between locking the sync.Mutex and invoking cond.Wait. To demonstrate this, an artificial delay was introduced into the main goroutine, simulating the race condition:
package main import ( "sync" "time" ) func main() { var m sync.Mutex var c = sync.NewCond(&m) go func() { time.Sleep(1 * time.Second) c.Broadcast() }() m.Lock() time.Sleep(2 * time.Second) c.Wait() }
Executing this code results in a deadlock panic due to the goroutine waiting for a condition that has not been signaled yet.
Addressing the Race Condition
The correct approach to avoid this race condition is to ensure that the sync.Mutex is locked before calling cond.Wait. This prevents other goroutines from modifying the shared data while the current goroutine is waiting on a condition:
package main import ( "sync" "time" ) func main() { var m sync.Mutex var c = sync.NewCond(&m) go func() { time.Sleep(1 * time.Second) m.Lock() c.Broadcast() m.Unlock() }() m.Lock() c.Wait() m.Unlock() }
Alternative Synchronization Constructs
While sync.Cond can be useful in scenarios where multiple goroutines wait for a shared resource to become available, it is important to consider alternative synchronization primitives. For instance, if you have a one-to-one relationship between a writer and reader, a sync.Mutex may suffice for communication:
var sharedRsc = make(map[string]interface{}) func main() { m := sync.Mutex{} go func() { m.Lock() sharedRsc["rsc1"] = "foo" m.Unlock() }() m.Lock() fmt.Println(sharedRsc["rsc1"]) m.Unlock() }
In cases where multiple readers are involved, channels offer a more efficient and scalable solution for passing data around.
The above is the detailed content of How to Avoid Race Conditions When Using sync.Cond for Conditional Waiting?. For more information, please follow other related articles on the PHP Chinese website!