1. 程式人生 > >62-條件變數結構體Cond

62-條件變數結構體Cond

 




條件變數結構體
Cond


先看一下Cond的原始碼

type Cond struct {
	noCopy noCopy

	// L is held while observing or changing the condition
	L Locker        // 在條件變數中有把鎖

	notify  notifyList
	checker copyChecker
}


條件變數結構體中有一把鎖
所以條件變數就可以有加鎖和解鎖的功能


再說一下條件變數Cond的方法

方法一:func (c *Cond) Wait():  


方法二:func (c *Cond) Signal():喚醒一個人


方法三:func (c *Cond) Broadcast():喚醒所有的人(驚群)



wait的功能有三個


1、阻塞


2、解鎖


3、加鎖


說一下方法的具體細節

1.wait一旦阻塞,就不會自動去搶鎖
需要被喚醒後才能去搶鎖
wait需要被signal或者broadcast喚醒

wait解鎖並且阻塞當前的執行緒
需要呼叫broadcast或者signal喚醒後
執行緒才恢復執行
不會主動醒過來

2.signal喚醒等待c的一個執行緒
在呼叫這個方法的時候,建議是保持c.L的鎖定
單發通知: 給一個wait的執行緒傳送通知

3.broadcast喚醒所有wait的執行緒,建議保持鎖定
廣播通知: 給所有wait的執行緒傳送通知


我們來一個例子


var cond sync.Cond				//條件變數
//生產者
func producer(in chan<- int){
	for  {
		cond.L.Lock()
		for len(in)==3{
			cond.Signal()
			cond.Wait()	//阻塞——解鎖——加鎖
		}
		num:=rand.Intn(100)
		fmt.Println("生產了",num)
		in<-num
		//cond.Broadcast()		//驚群
		cond.L.Unlock()
	}
}
//消費者
func consumer(out <-chan int )  {
	for  {
		cond.L.Lock()
		for len(out)==0{
			cond.Signal()
			cond.Wait()		//阻塞——解鎖——加鎖
		}
		num:=<-out
		fmt.Println("消費了:",num)
		//cond.Broadcast()		//驚群
		cond.L.Unlock()
	}
}

func main() {
	rand.Seed(time.Now().UnixNano())		//隨機種子
	cond.L=new(sync.Mutex)					//條件變數中的鎖
	c:=make(chan int,3)						//緩衝區
	for i:=1;i<=5 ;i++  {					//5個協程併發生產
		go producer(c)
	}
	for i:=1;i<=5 ;i++  {					//5個協程併發消費
		go consumer(c)
	}
	select {

	}
}