go条件变量的使用和原理
场景
最近写代码时碰到一个场景, 需要使用 map[int]struct{} 结构来存储task, map的key是task的id,随时可以增减。因为的确除了看书,基本上没使用过条件变量所以后面过了一天才想到可以用条件变量来实现。记得在某篇博客上看到的一句话挺不错,大概是同步语句中,条件变量的特点在于等待。
一开始代码大概是这样的
事件循环
func Loop() {
for {
mutex.Lock()
for taskId, task := range tasks {
// handle code
}
lenght := len(task)
mutex.UnLock()
// 为了减少cpu空转 当队列为空的时候sleep 2秒
if length == 2 {
time.Sleep(time.Secord * 2)
}
}
}
新增task(删除也是类似)
func addTask(t *Task) {
mutex.Lock()
tasks[t.Id] = t
mutex.UnLock()
}
使用条件变量
使用条件变量之后的事件循环代码
func Loop() {
for {
mutex.Lock()
// 如果当前任务数为0 调用Wait()等待新任务增加时唤醒
if len(tasks) == 0 {
cond.Wait() // cond := sync.NewCond(&mutex)
}
for taskId, task := range tasks {
// handle code
}
mutex.UnLock()
}
}
新增task(删除task代码不作改变)
func addTask(t *Task) {
mutex.Lock()
tasks[t.Id] = t
if len(task) == 1 { // 从0->1 可能之前有goruntine阻塞
cond.Signal() // 由于Loop()是单协程在跑所以 使用的是Signal()足矣
}
mutex.UnLock()
}
条件变量原理(和语言无关)
如果是C语言的pthread_cond条件变量和GO最主要的区别,本质上还是协程和真正的内核线程的区别, go 自带sync包里的条件变量 对goruntine的操作,其阻塞/唤醒不需要陷入内核态。
Wait()
func (c *Cond) Wait() {
c.checker.check()
t := runtime_notifyListAdd(&c.notify) // 等待的goruntine数+1
c.L.Unlock() // 释放锁资源
runtime_notifyListWait(&c.notify, t) // 阻塞,等待其他goruntine唤醒
c.L.Lock() // 获取资源
}
Signa() 和 BroadCast()
func (c *Cond) Signal() {
c.checker.check()
runtime_notifyListNotifyOne(&c.notify) // 唤醒最早被阻塞的goruntine
}
func (c *Cond) Broadcast() {
c.checker.check()
runtime_notifyListNotifyAll(&c.notify) // 唤醒所有goruntine
}
go条件变量的使用和原理的更多相关文章
- 深入理解Solaris内核中互斥锁(mutex)与条件变量(condvar)之协同工作原理
在Solaris上写内核模块总是会用到互斥锁(mutex)与条件变量(condvar), 光阴荏苒日月如梭弹指一挥间,Solaris的大船说沉就要沉了,此刻心情不是太好(Orz).每次被年轻的有才华的 ...
- Linux 多线程条件变量同步
条件变量是线程同步的另一种方式,实际上,条件变量是信号量的底层实现,这也就意味着,使用条件变量可以拥有更大的自由度,同时也就需要更加小心的进行同步操作.条件变量使用的条件本身是需要使用互斥量进行保护的 ...
- C++11 中的线程、锁和条件变量
转自:http://blog.jobbole.com/44409/ 线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通 ...
- node源码详解(七) —— 文件异步io、线程池【互斥锁、条件变量、管道、事件对象】
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource7 本博客同步在https://cnodejs.o ...
- linux 条件变量与线程池
条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...
- 非常精简的Linux线程池实现(一)——使用互斥锁和条件变量
线程池的含义跟它的名字一样,就是一个由许多线程组成的池子. 有了线程池,在程序中使用多线程变得简单.我们不用再自己去操心线程的创建.撤销.管理问题,有什么要消耗大量CPU时间的任务通通直接扔到线程池里 ...
- 【转】【C++】C++ 中的线程、锁和条件变量
线程 类std::thread代表一个可执行线程,使用时必须包含头文件<thread>.std::thread可以和普通函数,匿名函数和仿函数(一个实现了operator()函数的类)一同 ...
- 深入浅出 Java Concurrency (9): 锁机制 part 4 锁释放与条件变量 (Lock.unlock And Condition)
本小节介绍锁释放Lock.unlock(). Release/TryRelease unlock操作实际上就调用了AQS的release操作,释放持有的锁. public final boolean ...
- linux io 学习笔记(02)---条件变量,管道,信号
条件变量的工作原理:对当前不访问共享资源的任务,直接执行睡眠处理,如果此时需要某个任务访问资源,直接将该任务唤醒.条件变量类似异步通信,操作的核心:睡眠.唤醒. 1.pthread_cond_t 定 ...
随机推荐
- 又一款dump文件观察工具---MiniDumpView
简介 MiniDumpView实用程序可用于显示minidump中数据流的内容.特别是,可以显示以下信息: 操作系统和CPU信息 进程信息(进程ID和时间) 模块列表(包含每个模块的详细信息) 线程列 ...
- chef test-kitchen Could not load the 'vagrant' driver from the load path 问题解决
今天使用chef 的kitchen,运行kitchen list 发现了如下错误: >>>>>> ------Exception------- >>&g ...
- redis windows版本的使用
ServiceStack的redis-windows下载 下载新的版本解压到硬盘,使用黑窗口切换到路径后执行 redis-server redis.windows.conf 即可看到redis启动到6 ...
- 数据结构实验之排序四:寻找大富翁(SDUT 3401)
#include <stdio.h> #include <stdlib.h> #include <string.h> void Swap(int a[], int ...
- 什么是TCP粘包?怎么解决这个问题
在socket网络编程中,都是端到端通信,由客户端端口+服务端端口+客户端IP+服务端IP+传输协议组成的五元组可以明确的标识一条连接.在TCP的socket编程中,发送端和接收端都有成对的socke ...
- Linux 磁盘的分区
如果我们想在系统中新增一块硬盘,需要做什么呢? 1. 对磁盘进行分区,新建可用分区 2. 对该分区进行格式化,以创建系统可用的文件系统 3. 若想要仔细一点,可以对刚才新建好的文件系统进行检验 4. ...
- golang模拟编程tcp模拟http(转载)
package main import ( "fmt" "net" "strconv" ) //用来转化int为string type In ...
- Lararel安装和虚拟主机配置
Laravel 对系统有些要求,当然,所有这些要求 Laravel Homestead 虚拟机都能满足,因此强烈推荐你使用 Homestead 作为你的开发环境. 当然,假如你不使用 Homestea ...
- #C++初学记录(ACM8-6-cf-f题)
F. Vanya and Label While walking down the street Vanya saw a label "Hide&Seek". Becaus ...
- ggplot常见语法汇总查询
主图 散点图 柱状图 折线图 小提琴图 点图 进化树 圈图 Alluvial图 Sankey Diagram plot(getSankey(colData(muraro)$cell_type1, mu ...