Golang语言goroutine协程并发安全及锁机制

news/2025/1/15 20:58:01/文章来源:https://www.cnblogs.com/yinzhengjie/p/18341336

                                              作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

目录
  • 一.多协程操作同一数据问题引出
  • 二.互斥锁Mutex
    • 1 互斥锁概述
    • 2使用互斥锁Mutex同步协程
  • 三.读写互斥锁RWMutex
    • 1 读写互斥锁概述
    • 2 读写锁RWMutex引入

一.多协程操作同一数据问题引出

package mainimport ("fmt""sync"
)var (count intwg    sync.WaitGroup
)func add() {defer wg.Done()for i := 1; i <= 1000000; i++ {count++}
}func sub() {defer wg.Done()for i := 1; i <= 1000000; i++ {count--}
}func main() {// 开启2个协程等待wg.Add(2)go add()go sub()wg.Wait()// 在理论上,这个count结果应该是0,无论协程怎么交替执行,最终咱们想象的结果就是0,但事实上并不是!!!// 那为什么结果不为0呢?可以参考上图的流程,最终值不为0的执行思路。fmt.Printf("count = %d\n", count)
}

二.互斥锁Mutex

1 互斥锁概述

方法名 功能
func (m *Mutex) Lock() 获取互斥锁
func (m *Mutex) Unlock() 释放互斥锁
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同一时间只有一个goroutine可以访问共享资源。Go语言中使用sync包中提供的Mutex类型来实现互斥锁。使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁。当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒的策略是随机的。

2使用互斥锁Mutex同步协程

package mainimport ("fmt""sync"
)var (count intwg    sync.WaitGroup/*互斥锁:"sync.Mutex"为互斥锁,"Lock()"进行加锁,"Unlock()"进行解锁。使用"Lock()"加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁。互斥锁适用于读写不确定场景,即读写次数没有明显的区别,性能相对来说比较低(因为同一个时刻仅有一个协程可以操作)。*/lock sync.Mutex
)func add() {defer wg.Done()for i := 1; i <= 1000000; i++ {// 加锁,确保一个协程在执行逻辑的时候另外的协程不被执行。lock.Lock()count++// 解锁lock.Unlock()}
}func sub() {defer wg.Done()for i := 1; i <= 1000000; i++ {// 加锁lock.Lock()count--// 解锁lock.Unlock()}
}func main() {// 开启2个协程等待wg.Add(2)go add()go sub()wg.Wait()// 使用互斥锁同步协程,从而解决多协程在对同一个资源处理时数据同步的问题。fmt.Printf("count = %d\n", count)
}

三.读写互斥锁RWMutex

1 读写互斥锁概述

方法名 功能
func (rw *RWMutex) Lock() 获取写锁
func (rw *RWMutex) Unlock() 释放写锁
func (rw *RWMutex) RLock() 获取读锁
func (rw *RWMutex) RUnlock() 释放读锁
func (rw *RWMutex) RLocker() Locker 返回一个实现Locker接口的读写锁
互斥锁是完全互斥的,但是实际上有很多场景是读多写少的,当我们并发的去读取一个资源而不涉及资源修改的时候是没有必要加互斥锁的。这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。sync.RWMutex提供了如上表所示的5个方法。读写锁分为两种:读锁和写锁。当一个goroutine获取到读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待。而当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。

2 读写锁RWMutex引入

package mainimport ("fmt""sync""time"
)var (/*读写锁:RWMutex是一个读写锁,其经常用于读次数远远多于写次数的场景。读写锁的好处是多个协程同时在读的时候,数据之间不产生影响,锁不产生影响。但多个协程出现了同时读和写的情况下才会产生影响,锁就会产生影响。*/lock sync.RWMutexwg sync.WaitGroup
)func read(id int) {defer wg.Done()// 加读锁,如果只是读数据,那么这个锁不产生影响,但是读写同时发生的时候,就会有影响lock.RLock()fmt.Printf("开始读取数据...ID = %d\n", id)time.Sleep(time.Second * 5)fmt.Printf("读取数据完成...ID = %d\n", id)// 解读锁lock.RUnlock()}func write() {defer wg.Done()lock.Lock()fmt.Printf("开始修改数据...\n")time.Sleep(time.Second * 3)fmt.Printf("修改数据完成...\n")lock.Unlock()}func main() {wg.Add(11)// 启动协程: 模拟"读多写少"场景,10个线程读(无视锁),总耗时仅需5秒。for i := 1; i <= 10; i++ {go read(i)}go write()wg.Wait()fmt.Println("main程序运行完成,程序已退出!")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/777428.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[rCore学习笔记 021]多道程序与分时任务

写在前面 本随笔是非常菜的菜鸡写的。如有问题请及时提出。 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 导读 这里就是第三章的开头了,由于我的巨菜,导致天天半天理解不了关键点所在,唉,实在是太折磨人. 遵照上一章开头的时候的优良传…

基于FPGA的2FSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR

1.算法仿真效果本系统在以前写过的FSK调制解调系统的基础上,增加了高斯信道模块,误码率统计模块,可以验证不同SNR情况下的FSK误码情况。vivado2019.2仿真结果如下(完整代码运行后无水印):SNR=16dbSNR=10dbSNR=5dbSNR=0dbRTL结构图如下:2.算法涉及理论知识概要频移键控是…

Contest5400 - 网络流-1

RTContest A 签到题 B 最大流 Dinic 板子。 Dinic 的整体结构: ll dinic() {ll ans = 0;while (bfs()) { // 如果 s 还有能到 t 的增广路fill(cur+1, cur+n+1, 0); // 当前弧优化的预处理,暂时不用管ans += dfs(s, INF); // 多路增广}return ans; }BFS 建分层图: bool bfs()…

MySQL45讲基础篇

基础篇 01 | 基础架构:一条SQL查询语句是如何执行的? 你好,我是林晓斌。 这是专栏的第一篇文章,我想来跟你聊聊 MySQL的基础架构。我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于MySQL的学习也是这样。平…

Datawhale AI 暑期夏令营 第四期Task3

Transformer架构 Transformer是一种用于自然语言处理(NLP)和其他序列到序列(sequence-to-sequence)任务的深度学习模型架构,它在2017年由Vaswani等人首次提出。Transformer架构引入了自注意力机制(self-attention mechanism),这是一个关键的创新,使其在处理序列数据时…

基于IEEE802.11g标准的OFDM信号帧检测matlab仿真

1.程序功能描述现有的无线通信信道共享的无线信号识别为将来的软件定义的无线电系统是一个巨大的挑战。在这个项目中,学生将制定IEEE802.11无线信号在AWGN信道,利用MATLAB/ Simulink技术来识别。一个完整的发射机模式将开发和实施。 在AWGN信道下的性能进行评估。基于IEEE802…

羽毛球比赛积分系统03

羽毛球比赛积分系统 1、产品愿景目标用户 学校的体育工作人员(老师、教练、裁判),学生和教师选手,赛事组织者,志愿者等羽毛球比赛的参与者。他们的需要或机会简化赛事安排和管理。 提高比赛的公正性和透明度。 实时掌握比赛成绩和排名。 增强赛事互动和参与体验。产品名称…

实现一个终端文本编辑器来学习golang语言:第二章Raw模式下的输入输出

从第二章开始,在每个小节的最后都会有一些代码实操作业,你可以选择自己完成(比较推荐),再对照我的实现方式,当然也可以直接看我的代码实现。不过,之后的各个功能实现,我都会基于我先前的代码实现版本,在它的基础上进行扩展。 首先,我们先来解决第一章遗留的第一个问题…

protobuf pwn题专项

protobuf pwn 准备工作 安装protobuf编译器 sudo apt-get install libprotobuf-dev protobuf-compiler 安装python依赖库 pip3 install grpcio pip3 install grpcio-tools googleapis-common-protos安装pbtk git clone https://github.com/marin-m/pbtkggbond 来自DubheCTF202…

JAVA游戏源码:魔塔大学生练手项目java学习项目

学习java朋友们,福利来了,今天小编给大家带来了一款魔塔源码。注意:此源码仅供学习使用!! 视频演示 源码搭建和讲解 启动main入口://************************************************************************ // ************完整源码移步: gitee典康姆/hadluo/java_g…

第五周进度报告

这周主要学习了java的一些基础知识,接下来的任务继续学习javaAPI部分的知识 鼠标监听机制 - MouseListener键盘监听机制 -KeyListener常用APIpackage me.Study;public class Test {public static void main(String[] args) {//获取到当前时间的毫秒值long start = System.curre…