条件等待和互斥锁有不同,互斥锁是不同协程公用一个锁,条件等待是不同协程各用一个锁,但
是wait()方法调用会等待(阻塞),直到有信号发过来,不同协程是共用信号。
Wait() 阻塞当前协成
func (c *Cond) Wait() {
c.checker.check()
t := runtime_notifyListAdd(&c.notify) // 等待的goruntine数+1
c.L.Unlock() // 释放锁资源
runtime_notifyListWait(&c.notify, t) // 阻塞,等待其他goruntine唤醒
c.L.Lock() // 获取资源
}
Signa() 和 BroadCast() 唤醒协成
func (c *Cond) Signal() {
c.checker.check()
runtime_notifyListNotifyOne(&c.notify) // 唤醒最早被阻塞的goruntine
}
func (c *Cond) Broadcast() {
c.checker.check()
runtime_notifyListNotifyAll(&c.notify) // 唤醒所有goruntine
}
demo
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var cond sync.Cond
//生产者
func producer(out chan<- int, index int){
for{
cond.L.Lock()
for len(out) == 10 {
fmt.Println(index, "len == 10")
cond.Wait()//阻塞 等待
}
num := rand.Intn(800)
time.Sleep(time.Second)
out<- num
fmt.Println("生产者:",index, num)
cond.L.Unlock()
cond.Signal()//唤醒阻塞的协程
}
}
//消费者
func consumer(in <-chan int, index int){
for{
cond.L.Lock()
for len(in) == 0 {
fmt.Println(index, "len == 0")
cond.Wait()//阻塞 等待
}
time.Sleep(time.Second)
num := <-in
fmt.Println("消费者:",index,num)
cond.L.Unlock()
cond.Signal()//唤醒阻塞的协程
}
}
func main() {
ch := make(chan int, 10)
rand.Seed(time.Now().UnixMilli())
cond.L = new(sync.Mutex)
for i:=1; i<=4; i++{
go producer(ch, i)
}
for i:=1; i<=6; i++{
go consumer(ch, i)
}
quit := make(chan []struct{})
<-quit
}
demo2
package main
import (
"fmt"
"sync"
"time"
)
var (
done = false
topic = "Golang梦工厂"
)
func main() {
cond := sync.NewCond(&sync.Mutex{})
go Consumer(topic,cond)
go Consumer(topic,cond)
go Consumer(topic,cond)
Push(topic,cond)
time.Sleep(5 * time.Second)
}
func Consumer(topic string,cond *sync.Cond) {
cond.L.Lock()
for !done{
cond.Wait()
}
fmt.Println("topic is ",topic," starts Consumer")
cond.L.Unlock()
}
func Push(topic string,cond *sync.Cond) {
fmt.Println(topic,"starts Push")
cond.L.Lock()
done = true
cond.L.Unlock()
fmt.Println("topic is ",topic," wakes all")
cond.Broadcast()
}
// 运行结果
//Golang梦工厂 starts Push
//topic is Golang梦工厂 wakes all
//topic is Golang梦工厂 starts Consumer
//topic is Golang梦工厂 starts Consumer
//topic is Golang梦工厂 starts Consumer