《7天学会Go并发编程》第六天 go语言Sync.cond的应用和实现 go实现多线程联合执行

本文介绍 sync.Cond 的基本概念与使用方法,包括初始化、简单使用、Broadcast 和 Signal 方法的应用,并探讨其内部原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

目录

文章目录

前言

一、sync.Cond是什么

二、sync.Cond的使用

1. Sync.Cond初始化

2.Sync.Cond简单使用

3.Sync.Cond的BroadCast方法使用

4.Sync.Cond的Signal()方法使用

三、Cond的内部原理

总结



前言

前面的编程文章主要介绍了并发编程的一些原理和应用,主要解决了并发编程中的临界资源保护问题、多线程之间的通信问题、多线程执行顺序问题。但是在实际编程中,也会遇到一类常见问题就是多线程之间的条件执行。多线程之间的条件执行讲的是多个线程出于等待状态,接收到对应的信号后执行。举一个生活化的场景:很多人排队等公交车,每个人都做好了上车的准备,但是车还没有来。只能等,盼星星,盼月亮,公交车来了。公交车来了以后,对于排队候车的人来讲,会有两种情况:1、成功上车2、因为人太多,车辆拒载,没有排上座位。在这个例子当中,公交车上就是那个等待条件,并且发出接纳多少人上车的指令。

一、sync.Cond是什么

   sync.Cond位于sync.package的包中,主要功能是提供一个临时变量。通过这个临时变量实现了等待条件不满足时,线程阻塞、等待条件满足后,线程再执行的功能。 

二、sync.Cond的使用

1. Sync.Cond初始化

Cond初始化的过程中,需要传入一个Mutex类型的参数。

package main

import "sync"

func main() {
	mutex := sync.Mutex{}
	cond := sync.NewCond(&mutex)
}

 

2.Sync.Cond简单使用

下文实现一个简单的Cond使用,实现先开启一个go线程等待,线程阻塞等待至cond.BroadCast执行,实现对等待线程的唤醒。

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	signal := 1
	mutex := sync.Mutex{}
	cond := sync.NewCond(&mutex)
	go func() {
		cond.L.Lock()
		for signal == 1 {
			fmt.Println("线程开始等待")
			cond.Wait()
			fmt.Println("线程等待结束")
		}
		cond.L.Unlock()
	}()
	time.Sleep(200*time.Millisecond)
	cond.Broadcast()
	signal=0
	time.Sleep(200*time.Millisecond)

}

3.Sync.Cond的BroadCast方法使用

下文实现一个BroadCast应用,实现10个线程同时阻塞等待,条件变量执行BroadCase后,所有线程并发执行。因为使用的是BroadCast的方法,唤醒所有等待线程,所以使用waitGroup管理批量线程执行。

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	signal := 1
	mutex := sync.Mutex{}
	cond := sync.NewCond(&mutex)
	group := sync.WaitGroup{}
	group.Add(10)
	for i := 0; i < 10; i++ {
		go func(int1 int) {
			defer group.Done()
			cond.L.Lock()
			for signal == 1 {
				fmt.Printf("线程%d开始等待\n",int1)
				cond.Wait()
				fmt.Printf("线程%d结束\n",int1)
			}
			cond.L.Unlock()
		}(i)
	}
	time.Sleep(200*time.Millisecond)
	cond.Broadcast()
	signal=0
	group.Wait()
}

 对应的执行效果:

线程4开始等待
线程9开始等待
线程5开始等待
线程6开始等待
线程7开始等待
线程8开始等待
线程1开始等待
线程0开始等待
线程2开始等待
线程3开始等待
线程3结束
线程2结束
线程7结束
线程4结束
线程9结束
线程5结束
线程6结束
线程1结束
线程0结束
线程8结束

Process finished with the exit code 0
 

4.Sync.Cond的Signal()方法使用

下文实现一个BroadCast应用,实现10个线程同时阻塞等待,条件变量执行Signal后,所有线程并发抢占。因为使用的是Signal的方法,只会有一个线程会被执行。这个选择规则就是先到先得谁第一个等待,谁就第一个执行。

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	signal := 1
	mutex := sync.Mutex{}
	cond := sync.NewCond(&mutex)
	c := make(chan  struct{}, 1)
	for i := 0; i < 10; i++ {
		go func(int1 int) {
			defer func() {
				c<- struct{}{}
			}()
			cond.L.Lock()
			for signal == 1 {
				fmt.Printf("线程%d开始等待\n",int1)
				cond.Wait()
				fmt.Printf("线程%d结束\n",int1)
			}
			cond.L.Unlock()
		}(i)
	}
	time.Sleep(200*time.Millisecond)
	cond.Signal()
	signal=0
	<-c
}

对应的执行效果:

 线程0开始等待
线程9开始等待
线程2开始等待
线程3开始等待
线程4开始等待
线程5开始等待
线程6开始等待
线程7开始等待
线程8开始等待
线程1开始等待
线程0结束


三、Cond的内部原理

核心源码如下:

func (c *Cond) Wait() {
	c.checker.check()
	t := runtime_notifyListAdd(&c.notify)  //添加线程到等到等待队列
	c.L.Unlock()
	runtime_notifyListWait(&c.notify, t) //让等待队列的线程开始等待
	c.L.Lock()
}

总结

        以上就是今天要讲的内容,本文仅仅简单介绍了cond的使用,Cond提供了一种可以县实现多线程协同执行的机制。这种机制应用到了很多的工程中,后续会陆续更新一些相关的内容。

        欢迎各位大佬多提宝贵意见,多多留言互动~

 

 

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大锤爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值