What can it be used for?
Cond in Golang's sync package implements a condition variable that can use multiple Readers to wait for public resources.
Each Cond will be associated with a Lock. When modifying the condition or calling the Wait method, the lock must be added to protect the Condition. A bit similar to Wait and NotifyAll in Java.
Condition variables are used to coordinate goroutines that want to share resources. When the state of the shared resources changes, they can be used to notify goroutines blocked by mutexes.
The difference between
Based on mutex locks, what is the difference between mutex locks?
It is usually used to protect critical areas and shared resources, and condition variables are used to coordinate shared resources you want to access.
Use scenarios
There is a coroutine that is receiving data, and other coroutines must wait for the coroutine to receive the data before they can read the correct data.
In the above situation, if you simply use channel or mutex lock, you can only have one coroutine that can wait and read the data, and there is no way to notify other coroutines to read the data.
What to do at this time?
- A global variable can be used to identify whether the first coroutine has received data. The remaining coroutines repeatedly check the value of the variable until the data is read.
- Multiple channels can also be created, each coroutine blocks on one channel, and the coroutine that receives the data will be notified one by one after the data is received.
Then there is actually a built-in in Go to solve this problem.
// Each Cond has an associated Locker L (often a *Mutex or *RWMutex), // which must be held when changing the condition and // when calling the Wait method. // // A Cond must not be copied after first use. type Cond struct { noCopy noCopy // L is held while observing or changing the condition L Locker notify notifyList checker copyChecker }
You can see that each Cond will be associated with a lock L (mutex, or read-write lock * RMMutex). When modifying conditions or using Wait, you must add a lock.
What are the methods
NewCond Create an instance
func NewCond(l Locker) *Cond
NewCond Create an instance requires a lock associated.
Specific examples:
cadence := (&{})
Broadcast wakes up all
// Broadcast wakes all goroutines waiting on c. // // It is allowed but not required for the caller to hold // during the call. func (c *Cond) Broadcast()
Broadcast wakes up all goroutines of waiting condition variable c without lock protection.
Specific examples:
go func() { for range (1 * ) { () } }()
Signal Wake up a coroutine
// Signal wakes one goroutine waiting on c, if there is any. // // It is allowed but not required for the caller to hold // during the call. func (c *Cond) Signal()
Signal only wakes up the goroutine of any one waiting condition variable c, without lock protection. A bit similar to Notify in Java
Wait Wait
// Wait atomically unlocks and suspends execution // of the calling goroutine. After later resuming execution, // Wait locks before returning. Unlike in other systems, // Wait cannot return unless awoken by Broadcast or Signal. // // Because is not locked when Wait first resumes, the caller // typically cannot assume that the condition is true when // Wait returns. Instead, the caller should Wait in a loop: // // () // for !condition() { // () // } // ... make use of condition ... // () // func (c *Cond) Wait()
Calling Wait will automatically release the lock and hang the goroutine where the caller is located, so the current coroutine will block where the Wait method is called. If other coroutines call Signal or Broadcast and wake up the coroutine, when the Wait method ends blocking, it relocks and continues to execute the code behind Wait
Code example:
() for !condition() { () } ... make use of condition ... ()
Code Example
package sync import ( "log" "sync" "testing" "time" ) var done = false func read(name string, c *) { () for !done { () } (name, "starts reading") () } func write(name string, c *) { (name, "starts writing") () () done = true () (name, "wakes all") () } func TestSyncCond(t *) { cond := (&{}) go read("reader1", cond) go read("reader2", cond) go read("reader3", cond) write("writer", cond) ( * 3) }
Running results
=== RUN TestSyncCond
2021/08/26 11:06:48 writer starts writing
2021/08/26 11:06:49 writer wakes all
2021/08/26 11:06:49 reader3 starts reading
2021/08/26 11:06:49 reader2 starts reading
2021/08/26 11:06:49 reader1 starts reading
--- PASS: TestSyncCond (4.01s)
PASS
This is the end of this article about the detailed explanation of the use of Go language. For more related Go content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!