博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
同步之条件变量sync.Cond
阅读量:6157 次
发布时间:2019-06-21

本文共 3634 字,大约阅读时间需要 12 分钟。

hot3.png

同步之条件变量sync.Cond sync.Cond 的结构体

type Cond struct {	// L is held while observing or changing the condition	L Locker	sema    syncSema	waiters uint32 // number of waiters	checker copyChecker}

sync.Cond 的方法

//阻塞当前的goroutine//方法Wait会自动的对与该条件变量关联的那个锁进行解锁,并且使调用方所在的Goroutine被阻塞。//一旦该方法收到通知,就会试图再次锁定该锁。//如果锁定成功,它就会唤醒那个被它阻塞的Goroutine。//否则,该方法会等待下一个通知,那个Goroutine也会继续被阻塞。func (c *Cond) Wait() {	c.checker.check()	if race.Enabled {		race.Disable()	}        //原子递增等待者计数,然后获取信号量进入休眠	atomic.AddUint32(&c.waiters, 1)	if race.Enabled {		race.Enable()	}	c.L.Unlock()	runtime_Syncsemacquire(&c.sema)	c.L.Lock()}func (c *Cond) Signal() {}func (c *Cond) Broadcast() {}

先看一个简单的用法,这样一个场景: 在控制台输入enter,作为一个发送通知的信号,使阻塞的goroutine继续执行。

package mainimport (	"os"	"fmt"	"sync"	"time")func main() {	locker := sync.Mutex{}	cond := sync.NewCond(&locker)	go func() {		os.Stdin.Read(make([]byte, 1)) // read a single byte		cond.Signal()//当键盘输入enter后,发出通知信号		fmt.Println("signal...")	}()	go func() {		cond.L.Lock() //首先进行锁定,与之关联的条件变量的锁定		fmt.Println("wait before...")		//等待Cond消息通知		cond.Wait()		fmt.Println("wait end...")		cond.L.Unlock()	}()	time.Sleep(10 * time.Second)	fmt.Println("exit...")}

运行结果,

wait before...signal...wait end...exit...

在打印出wait before...后,然后在控制台输入空格,最后wait end。 问题来了,如果在wait 之前输入了enter怎么办,也就是说提前发出了信号怎么办?如下代码,

package mainimport (	"os"	"fmt"	"sync"	"time")func main() {	var wg sync.WaitGroup	locker := sync.Mutex{}	cond := sync.NewCond(&locker)	go func() {		os.Stdin.Read(make([]byte, 1)) // read a single byte		cond.Signal()//当键盘输入enter后,发出通知信号		fmt.Println("signal...")	}()	time.Sleep(5 * time.Second)	fmt.Println("sleep end...")	wg.Add(1)	go func() {		defer wg.Done()		cond.L.Lock() //首先进行锁定,与之关联的条件变量的锁定		fmt.Println("wait before...")		//等待Cond消息通知		cond.Wait()		fmt.Println("wait end...")		cond.L.Unlock()	}()	wg.Wait()	fmt.Println("exit...")}

运行结果,

signal...sleep end...wait before...fatal error: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:sync.runtime_Semacquire(0xc82000a28c)	/usr/local/go/src/runtime/sema.go:47 +0x26sync.(*WaitGroup).Wait(0xc82000a280)	/usr/local/go/src/sync/waitgroup.go:127 +0xb4main.main()	/Users/xinxingegeya/gogogo/ucar.com/cond/hello.go:36 +0x245goroutine 7 [semacquire]:sync.runtime_Syncsemacquire(0xc820010290)	/usr/local/go/src/runtime/sema.go:241 +0x201sync.(*Cond).Wait(0xc820010280)	/usr/local/go/src/sync/cond.go:63 +0x9bmain.main.func2(0xc82000a280, 0xc820010280)	/Users/xinxingegeya/gogogo/ucar.com/cond/hello.go:31 +0x159created by main.main	/Users/xinxingegeya/gogogo/ucar.com/cond/hello.go:34 +0x237exit status 2Process finished with exit code 1

在sleep end...之前输入enter,这时会发出信号,当sleep 结束之后,当执行接下来的goroutine时就会发生错误,即使wait了,也不会发出信号了。怎么才能避免这种情况呢?推荐用法如下,

package mainimport (	"fmt"	"os"	"sync"	"time")func main() {	var wg sync.WaitGroup	locker := sync.Mutex{}	cond := sync.NewCond(&locker)	var condition bool = false	go func() {		os.Stdin.Read(make([]byte, 1)) // read a single byte		cond.L.Lock()		cond.Signal()    //当键盘输入enter后,发出通知信号		condition = true //把条件变量设为true,表示发送过信号		fmt.Println("signal...")		cond.L.Unlock()	}()	time.Sleep(5 * time.Second)	fmt.Println("sleep end...")	wg.Add(1)	go func() {		defer wg.Done()		cond.L.Lock() //首先进行锁定,与之关联的条件变量的锁定		fmt.Println("wait before...")		//等待Cond消息通知		for !condition {			//当条件为真时,不会发生wait			fmt.Println("wait...")			cond.Wait()		}		fmt.Println("wait end...")		cond.L.Unlock()	}()	wg.Wait()	fmt.Println("exit...")}

在sleep 之前输入enter,

signal...sleep end...wait before...wait end...exit...

在sleep之后输入enter,

sleep end...wait before...wait...signal...wait end...exit...

=======END=======

转载于:https://my.oschina.net/xinxingegeya/blog/729197

你可能感兴趣的文章
在OSCHINA上的第一篇博文,以后好好学习吧
查看>>
Spring常用注解
查看>>
linux:yum和apt-get的区别
查看>>
Sentinel 1.5.0 正式发布,引入 Reactive 支持
查看>>
数据库之MySQL
查看>>
2019/1/15 批量删除数据库相关数据
查看>>
数据类型的一些方法
查看>>
Webpack 2 中一些常见的优化措施
查看>>
移动端响应式
查看>>
js中var、let、const的区别
查看>>
简洁优雅地实现夜间模式
查看>>
react学习总结
查看>>
在soapui上踩过的坑
查看>>
MySQL的字符集和字符编码笔记
查看>>
ntpd同步时间
查看>>
must implement java.io.Serializable hessian
查看>>
Microsoft Licenses Flash Lite for Windows Mobile Users
查看>>
HDOJ 2020 绝对值排序
查看>>
HDOJ/HDU 2560 Buildings(嗯~水题)
查看>>
Maven编译时跳过Test
查看>>