go语言条件变量

title: Go语言条件变量
tags: Go语言并发
categories: Go语言标准库


  • Go语言条件变量是基于互斥锁的,也就是通过互斥锁实现的。
  • 条件变量作用:条件变量并不能保护临界区和共享资源,主要是用来控制访问空闲资源的协程的状态。对阻塞的协程进行等待和唤醒动作。当满足某个条件时,协程才能对共享资源进行操作。
  • 简单举例使用
func main()  {
   var sign int
   var lock sync.Mutex
   receive:=sync.NewCond(&lock)
   send:=sync.NewCond(&lock)
   ch := make(chan struct{},3)
   //当sign = 1时发送数据,当sign=0时接受数据
   go func() {
   	defer func() {
   		ch<- struct{}{}
   	}()
   	for i := 0; i < 3; i++ {
   		lock.Lock()
   		for sign == 0 {
   			send.Wait()
   		}
   		sign = 0
   		fmt.Println("接受到了数据",i)
   		lock.Unlock()
   		receive.Signal()
   	}

   }()
   go func() {
   	defer func() {
   		ch<- struct{}{}
   	}()

   	for j := 4; j < 7; j++ {
   		lock.Lock()
   		for sign == 1{
   			receive.Wait()
   		}
   		sign = 1
   		fmt.Println("发送数据",j)
   		lock.Unlock()
   		send.Signal()

   	}
   }()
   	<-ch
   	<-ch
}
//运行结果
// 发送数据 4
// 接受到了数据 0
// 发送数据 5
// 接受到了数据 1
// 发送数据 6
// 接受到了数据 2

  • sync.Cond无法直接使用,需要sync.NewCond()函数生成,函数需要一个sync.Locker类型的参数值,sync.Locker是一个接口,有lock()和Unlock()两个方法,需要传入一个实现这两个方法的结构体指针,而互斥锁正好实现了这两个方法,所以从这里可以说条件变量是基于互斥锁的。

  • sync.Cond有三个方法,分别是Wait(),Signal(),Broadcast(),有这三个方法实现对协程的等待通知操作。

  • Wait()方法:

    1. 将调用它的goroutine(也就是当前的goroutine)加入到当前当前条件变量的等待队列。
    2. 自动对条件变量的互斥锁进行解锁,所以在使用wait()前要先进行加锁操作。
    3. 将当前goroutine设置成等待状态,只有条件变量通知(Signal()方法)时才觉得是否唤醒。后面的代码并不会继续执行。
    4. 当接到通知时会唤醒goroutine,在唤醒后会对条件变量进行加锁,然后继续执行后面的代码,注意会面的代码要对互斥锁进行解锁操作。
    • 注意事项:使用for语句可以对条件进行对此检查,使用if的话只能检查一次。主要是为了防止goroutine被唤醒时,条件任然不符合,那它应该继续等待。
  • Signal()方法:

    1. 通知处于等待状态中的一个goroutine,将其唤醒。Wait()方法会将goroutine放于等待队列的队尾,Signal()方法会从等待队列的队头开始唤醒
    2. Signal()并不需要在互斥锁的保护下进行,不过在通知时最好先对互斥锁进行解锁操作。
    3. 条件变量的通知具有即时性。也就是说,如果发送通知的时候没有 goroutine 为此等待,那么该通知就会被直接丢弃。在这之后才开始等待的 goroutine 只可能被后面的通知唤醒。
  • Broadcast()方法:

    1. 通知等待队列的所有goroutine,将其全部唤醒。
posted @ 2021-04-19 22:04  月下繁星杨  阅读(254)  评论(0编辑  收藏  举报