
Golang 标准库中提供了sync.Mutex 用于多线程之间的同步。
同时也提供了条件变量配合Mutex结合使用。
条件变量主要的使用场景是:
实例说明当线程要执行A *** 作时,条件B未满足,而无法执行A *** 作,此时使当前线程进入睡眠状态(进入睡眠状态前会释放锁),等待条件B,当条件B出现时,发送通知唤醒因等待条件B而进入沉睡的线程。
一条专门用于读取文件A的线程T1, 一条专门用于写入文件A的线程T2。通过锁M1做读写的同步 *** 作。当T1获取锁M1时,读取文件A,当读取到EOF时,不希望就此结束,而是希望等待,当T2向文件A写入内容后,又可以继续读出内容。此时T1应当释放锁并且通过条件变量进入睡眠状态,然后T2获取锁,对文件进行写入。写完之后释放锁,并且发送一个通知用于唤醒T1,T1被唤醒后,试图获取锁,获取成功后继续进行读 *** 作。
上面的例子中,通过条件变量唤醒睡眠的线程,有两种方式,Signal和broadcast,如果是Signal会在因当前条件变量而进入睡眠的线程中随机选取一条线程唤醒,然后该线程试图获取锁,如果获取成功,则执行之后的代码逻辑,如果未获取成功则会一直等待,直到获取锁。如果是broadcast,会将所有因当前条件变量而进入睡眠的线程全部唤醒,所有的线程一起去试图获取锁,哪一条线程先获取到,哪一条线程先执行,其余的线程则继续等待,直到上一次抢到锁的线程释放锁时,再一次开始对于锁的争抢。(注意这里的线程被条件变量唤醒之后,即使未抢到锁,也不再需要条件变量对其进行再一次的通知唤醒)
下面通过代码后打印结果来更深刻的体会package mainimport ( "sync" "fmt" "time" "math/rand")type T struct { l *sync.Mutex // 锁 c *sync.Cond //条件变量}func main() { wg := sync.WaitGroup{} wg.Add(1) var t *T = new(T) t.l = new(sync.Mutex) // 使用条件变量前,必须将其与一个锁绑定 t.c = sync.NewCond(t.l) //启动10条协程,当协程执行conditions()发现满足条件时,打印出processed,代表该协程处理结束 //当不满足条件时,通过条件变量进入睡眠状态,每次从睡眠状态醒来并且获取锁之后,打印出一条wait。 for i := 0; i < 10; i++ { go func() { t.l.Lock() defer t.l.Unlock() //不满足条件时通过条件变量进入沉入 //t.c.Wait() 首先会释放与该条件变量绑定的锁,然后在进入睡眠状态 for !conditions() { t.c.Wait() fmt.Println("wait") } fmt.Println("processed") }() } // 启动一条协程 每隔两秒发送一次通知 go func() { for { time.Sleep(time.Second * 2) //fmt.Println("\n\n\n\nbroadcast") //t.c.broadcast() fmt.Println("\n\n\n\nSignal") t.c.Signal() } }() wg.Wait()}//生成随机数, 当生成的数为0时,则为满足条件返回truefunc conditions() bool { i := rand.Intn(10) fmt.Println(i) if i == 0 { return true } else { return false }}打印结果
10条协程,在第一次执行时,两条随机出了0,处理完毕,剩余8条协程,通过条件变量进入睡眠状态。17791850processed60processed过两秒之后发出第一次广播,其中一条协程获取了锁,并且打印了wait进入conditions()随机出了7,为满足条件继续通过条件变量进入睡眠。Signalwait7同上Signalwait8再一次唤醒协程,此次conditions()随机出了0满足了条件,打印出processed,处理完毕。Signalwait0processed
从上面的打印结果可以看出每一次只唤醒了一条携程
接下来将代码中的
fmt.Println("\nSignal")t.c.Signal()
替换为
fmt.Println("\nbroadcast")t.c.broadcast()
再来打印输出结果进行分析
第一次打印出的结果和上面的一样主要看发送广播时的输出17791850processed60processed停了两秒发送了广播,此时所有关联在条件变量的协程都被唤醒。从结果可以看出,只发送了一次唤醒广播,所有的协程都打印了一遍wait,说明这些协程都被唤醒,并且依次获取了锁,然后执行。当然一个时间段内只能有一个协程获取到锁。broadcastwait7wait8wait0processedwait5wait1wait8wait7wait1总结
以上是内存溢出为你收集整理的Condition variables in Golang difference between Signal and Broadcast全部内容,希望文章能够帮你解决Condition variables in Golang difference between Signal and Broadcast所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)