文档章节

同步之条件变量sync.Cond

秋风醉了
 秋风醉了
发布于 2016/08/07 16:06
字数 820
阅读 233
收藏 0
点赞 1
评论 0

同步之条件变量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 main

import (
	"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 main

import (
	"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 +0x26
sync.(*WaitGroup).Wait(0xc82000a280)
	/usr/local/go/src/sync/waitgroup.go:127 +0xb4
main.main()
	/Users/xinxingegeya/gogogo/ucar.com/cond/hello.go:36 +0x245

goroutine 7 [semacquire]:
sync.runtime_Syncsemacquire(0xc820010290)
	/usr/local/go/src/runtime/sema.go:241 +0x201
sync.(*Cond).Wait(0xc820010280)
	/usr/local/go/src/sync/cond.go:63 +0x9b
main.main.func2(0xc82000a280, 0xc820010280)
	/Users/xinxingegeya/gogogo/ucar.com/cond/hello.go:31 +0x159
created by main.main
	/Users/xinxingegeya/gogogo/ucar.com/cond/hello.go:34 +0x237
exit status 2

Process finished with exit code 1

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

package main

import (
	"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=======

© 著作权归作者所有

共有 人打赏支持
秋风醉了
粉丝 223
博文 581
码字总数 411013
作品 0
东城
程序员
Golang Cond源码分析

cond的主要作用就是获取锁之后,wait()方法会等待一个通知,来进行下一步锁释放等操作,以此控制锁合适释放,释放频率,适用于在并发环境下goroutine的等待和通知。 针对Golang 1.9的sync.Co...

梦朝思夕 ⋅ 04/22 ⋅ 0

Golang sync.Cond源码分析

cond的主要作用就是获取锁之后,wait()方法会等待一个通知,来进行下一步锁释放等操作,以此控制锁合适释放,释放频率,适用于在并发环境下goroutine的等待和通知。 针对Golang 1.9的sync.Co...

梦朝思夕 ⋅ 04/23 ⋅ 0

互斥锁和条件变量

互斥锁和条件变量是出自Posix线程标准,用来同步一个进程中各个线程的,同时也可以用来同步几个进程间的,不过这需要此互斥锁和条件变量是存放在多个进程间共享的某个内存区的。 互斥锁上锁与...

chengyang ⋅ 2011/09/23 ⋅ 0

Java线程:条件变量 lock

条件变量是Java5线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量。但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含...

古月楼 ⋅ 2013/08/26 ⋅ 0

使goroutine同步的方法总结

前言: 在前面并发性能对比的文章中,我们可以看到Golang处理大并发的能力十分强劲,而且开发也特别方便,只需要用go关键字即可开启一个新的协程。 但当多个goroutine同时进行处理的时候,就会...

oneHand ⋅ 01/29 ⋅ 0

Linux多线程之线程同步

线程最大的特点就是资源的共享性,所以也就有了一个难点线程同步,实现线程同步的方法最常用的方法是:互斥锁,条件变量和信号量。接下来就让我们来看下这几种同步的方法。 一、互斥锁(Mut...

8yi少女的夢 ⋅ 2017/10/18 ⋅ 0

Linux——互斥锁与条件变量(二)

三、对比上锁与等待 在上述的生产者-消费者问题中,我们在实现同步的时候还可以用以下的方法来实现,这里只是说明与上述实现中的不同之处。 1、首先,说明一下此版本中的相关特征: 在此版本...

KiteRunner ⋅ 2014/06/02 ⋅ 0

第2章 线程安全性

在构建稳健的并发程序时,必须正确地使用线程和锁。但这些终归只是一些机制。要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态...

陶邦仁 ⋅ 2015/04/25 ⋅ 0

操作系统清华大学版笔记(十) 信号量、管程、条件互斥、经典同步问题(读者写者、哲学家问题)

10-1 信号量 Semaphore 一个整型int(sem),可进行两个原子操作 P() sem–,如果sem<0,等待,否则继续,类似lock_acquire V() sem++,如果sem<=0,说明当前有等着的,唤醒挂在信号量上的进...

xiaoshuaisdl ⋅ 04/10 ⋅ 0

python多线程(条件变量同步)

互斥锁是最简单的线程同步机制,Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方...

DragonRiver2015 ⋅ 2013/12/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 37分钟前 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 44分钟前 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 51分钟前 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

容器之查看minikue的environment——minikube的环境信息

执行如下命令 mjduan@mjduandeMacBook-Pro:~/Docker % minikube docker-envexport DOCKER_TLS_VERIFY="1"export DOCKER_HOST="tcp://192.168.99.100:2376"export DOCKER_CERT_PATH="/U......

汉斯-冯-拉特 ⋅ 昨天 ⋅ 0

mysql远程连接不上

设置了root所有hosts远程登录,可是远程登录还是失败,原因可能如下: 登录本地数据库 mysql -uroot -p123456 查询用户表 mysql> select user,host,password from mysql.user; 删除密码为空的...

冰公子 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部