记一次go协程读写锁 sync.RWMutex未释放导致其他协程阻塞bug

news2024/11/27 11:47:30

记一次go协程读写锁 sync.RWMutex未释放导致其他协程阻塞bug

  • 记一次go协程读写锁 sync.RWMutex未释放导致其他协程阻塞bug
    • 用到的监测工具
    • 程序简要介绍
    • 示例代码
    • 运行结果
    • 运行结果分析

记一次go协程读写锁 sync.RWMutex未释放导致其他协程阻塞bug

通过一个简单示例模拟某协程结束,但是对共享变量的锁未释放,导致其他访问该共享变量的协程阻塞的程序运行结果

用到的监测工具

  • http/pprof:一款用于golang程序运行时监测的工具,官网地址http/pprof

程序简要介绍

  • 从main函数开始
  • 初始化并运行监测程序:go StartHTTPDebuger()
  • 创建了一个共享变量:students ,供多个协程进行读写操作
  • 定义协程数量N,这里取200
  • 启动N个读协程,对students进行读操作QueryStudent
  • 启动N个写协程,对students进行写操作AddStudent
  • wg.Wait() 等待启动的读协程和写协程运行都运行结束,只有当所有的读协程和写协程运行结束才会运行wg.Wait()后面的代码
  • 运行程序,并在浏览器中输入http://localhost:8082/debug/pprof/goroutine?debug=1进行程序运行监测

示例代码

package main

import (
	"fmt"
	"net/http"
	"net/http/pprof"
	"strconv"
	"sync"
	"time"
)

type Student struct {
	id   string
	name string
}

func NewStudent(id, name string) *Student {
	return &Student{
		id:   id,
		name: name,
	}
}

type Students struct {
	mu   sync.RWMutex // 对共享变量stus的访问需要加的锁
	stus map[string]*Student
}

func (students *Students) AddStudent(student *Student) {
	students.mu.Lock()

	// AddStudent在协程中调用
	// 由于读协程和写协程用的是相同的锁Students.mu来访问相同的数据stus,而且在golang中sync.RWMutex是写优先
	// (读锁必须等待写锁释放),加上我们这里设置的条件,当满足这个条件时,直接返回,此时协程运行结束,此时写锁没有被释放(!!!!!)
	// 由于其他的写协程和读协程必须等待锁释放才能被调度运行,由于上面写锁一致释放不了,所以,那些等待锁的协程会阻塞(一直没办法继续往下运行)
	if student.id == "50" {
		// 不释放写锁,直接返回
		return
	}
	students.stus[student.id] = student
	students.mu.Unlock()
}

func (students *Students) QueryStudent(id string) *Student {
	students.mu.RLock()
	stu := students.stus[id]
	students.mu.RUnlock()
	return stu
}

const (
	pprofAddr string = ":8082"
)

func StartHTTPDebuger() {
	pprofHandler := http.NewServeMux()
	pprofHandler.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
	server := &http.Server{Addr: pprofAddr, Handler: pprofHandler}
	go server.ListenAndServe()
}

func main() {
	var wg sync.WaitGroup
	go StartHTTPDebuger()

	// 创建供写协程和读协程们访问的共享变量
	students := &Students{
		stus: make(map[string]*Student),
	}

	N := 200
	for i := 0; i < N; i++ {
		wg.Add(1)
		go func(index int) {
			defer wg.Done()
			time.Sleep(time.Second * 2)
			fmt.Println("query start:" + strconv.Itoa(index+1))
			stu := students.QueryStudent(strconv.Itoa(index + 1))
			fmt.Println("query end:" + strconv.Itoa(index+1))
			if stu != nil {
				fmt.Printf("id=%s, name=%s \n", stu.id, stu.name)
			}
		}(i)
	}

	for i := 0; i < N; i++ {
		wg.Add(1)
		go func(index int) {
			defer wg.Done()
			time.Sleep(time.Second * 1)
			fmt.Println("add start:" + strconv.Itoa(index+1))
			students.AddStudent(NewStudent(strconv.Itoa(index+1), "zhangsan_"+strconv.Itoa(index+1)))
			fmt.Println("add end:" + strconv.Itoa(index+1))
		}(i)
	}

	wg.Wait()                         // 等待wg的计数变为0(上面调用defer wg.Done()的所有协程运行结束)才会执行下面的代码
	fmt.Println("all goroutine done") // 不输出说明:至少存在一个协程没法运行结束
	for {
		time.Sleep(time.Second * 2)
	}
}

运行结果

  • wg.Wait()后面的代码一直没有输出:说明读协程、写协程至少有一个没有结束
  • 访问http://localhost:8082/debug/pprof/goroutine?debug=1发现:有160个写协程和200个读协程在等待锁,如下图所示
    在这里插入图片描述
  • 以上两点正好验证了当协程结束时,写锁未释放会造成的后果

运行结果分析

详见示例代码中的注释说明

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计电影院订票系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

第53篇 Qt Quick项目详解

导语 前面我们一起创建了一个Qt Quick项目&#xff0c;并对里面的文件进行了简单的讲解&#xff0c;虽然这只是一个HelloWorld程序&#xff0c;但对于没有Qt Quick编程经验的同学来说&#xff0c;这个项目还是有点复杂。在这一篇中&#xff0c;我们将从最简单的QML文件讲起&am…

Flutter Web CORS解决方案1-禁用浏览器安全策略

Flutter Web CORS解决方案1设置CHROME_EXECUTABLE关于 CHROME_EXECUTABLE创建 CHROME_EXECUTABLE修改 chrome.dart 禁用安全策略升级 flutterSDK 后需重新修改升级后指定--web-hostname参数问题浏览器启用 Allow-CORS 插件部分协议OPTIONS预检跨域问题本文介绍第一种解决Flutte…

《纳瓦尔宝典》笔记一——你是在跟自己竞争,这是一场单人游戏

目录 一、身体的健康是top1 二、你唯一拥有的就是时间 三、选择短期内更更痛苦的道路 四、人生早期有三个重大决定 五、从雇佣关系中解脱出来 六、找合作伙伴 七、你真的嫉妒别人吗 八、从期待中解放出来 九、向内求-内在的评价标准 十、人生的大赢家就是同时拥有时间…

[附源码]Nodejs计算机毕业设计基于RationalRose的教务管理系统开发Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

基于java+swing+mysql图书管理系统3

大作业-基于java swing图书管理系统3一、系统介绍二、功能展示1.管理员登陆2.图书类别添加3.图书类别维护4.图书添加5.图书维护三、系统实现1.BookManageMainFrame.java四、其它1.其他系统实现五.获取源码一、系统介绍 该系统实现了用户登陆、图书类别管理(图书类别添加、图书…

JavaEE 初始化两个上下文对象,导致更新网站访问次数更新失败

问题描述 &#xff1a; 在做网站次数统计的时候&#xff0c;需要用到上下文对象&#xff0c;最终在上下文监听中发现上下文对象创建两次&#xff0c;销毁两次&#xff0c;导致数据库中网站访问次数统计更新失败。 原因 &#xff1a; 我们更改了项目的访问路径&#xff0c;就会导…

使用Java实现上传图片到七牛云

文章目录1.登录七牛云官网&#xff0c;注册账号并登录2.在项目中导入七牛云依赖3.编写创建文件名工具类4.编写连接七牛云工具类5.编写前端请求的Controller6.上传成功1.登录七牛云官网&#xff0c;注册账号并登录 2.在项目中导入七牛云依赖 <!-- 七牛云依赖 --> <!-…

力扣1832.判断句子是否为全字母句(cpp实现+解析)

文章目录1832.判断句子是否为全字母句解法一解法二解法三&#xff08;最优&#xff09;1832.判断句子是否为全字母句 难度&#xff1a;简单 力扣传送门&#xff1a; https://leetcode.cn/problems/check-if-the-sentence-is-pangram/description/ 题目要求&#xff1a; 全字…

Compose学习 -> Image()

基本使用&#xff1a; 通过资源id加载资源文件 Image(painter painterResource(id R.mipmap.test_01),contentDescription "这是内容描述") 通过url地址加载网络图片 1、引入第三方库&#xff0c;并添加网络权限 implementation ("io.coil-kt:coil-comp…

【深入浅出Nacos原理及调优】「原理分析专题」配置中心加载原理和配置实时更新原理分析

官方资源 官方资源 带着问题去思考 客户端长轮询的响应时间会受什么影响为什么更改了配置信息后客户端会立即得到响应客户端的超时时间为什么要设置为30s带着以上这些问题我们从服务端的代码中去探寻结论。 配置中心 (Configuration Center) 系统开发过程中通常会将一些需…

用Python调用OpenAI API做有趣的事

获取 API KEY 首先需要 可以开全局的梯子&#xff0c;选择日本或韩国节点&#xff0c;可以通过 ipinfo 检查当前 IP 地址是否为日本或韩国地区&#xff0c;然后访问 OpenAI 网站注册账号并完成认证。 如果自己完成账号认证的成本太高&#xff0c;可以在某宝直接购买一个已经通…

存储也能“一键美颜”?看 XOCP 如何助力互联科技图片业务转型

近日&#xff0c;XSKY星辰天合联合“互联科技”推出了“图片云在线处理”解决方案&#xff0c;提供海量图片高效存储访问和在线图片处理服务&#xff0c;深入业务场景简化操作流程&#xff0c;提升照片流转速度&#xff0c;为客户打造高效敏捷的拍照体验。互联科技&#xff08;…

DAS Over FC 技术允许 ATTO 分解存储并完成 vSAN 认证套件

一、介绍 最近&#xff0c;ATTO Technology, Inc. 以前所未有的方式 完成了 VMware vSAN ReadyNode 认证套件。 测试台本身是公式化的&#xff0c;以三台 Dell R640 服务器作为主机。 除了用于引导的 SD 卡和用于日志记录的单个 SAS SSD 之外&#xff0c;不存在任何内部存储…

EXCEL基础:IFNA、VLOOKUP、SUMIFS函数的使用

注意&#xff1a;本操作数据来源于excel home&#xff0c;特此声明。 查看原始数据&#xff0c;如下所示为【商品】的相关信息&#xff1a; 查看原始数据&#xff0c;如下所示为【供应商】的相关信息&#xff1a; 主要目的&#xff1a;把以上相关信息搞在一张表上。 把下表…

基于jsp+mysql+ssm台球俱乐部管理系统-计算机毕业设计

项目介绍 台球俱乐部系统设计主要是管理员登录后对整个系统相关操作进行处理&#xff0c;可进行管理员的添加和删除&#xff0c;会员信息管理、付费信息管理、球桌信息管理、订桌信息管理等操作管理。采用目前最流行的ssm框架和eclipse编辑器、mysql数据库设计并实现的 本系统…

[附源码]计算机毕业设计冬奥会网上商城Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

什么是BPM系统?BPM流程管理系统介绍

一、什么是BPM系统&#xff1f; BPM系统&#xff08;英文全称&#xff1a;Business Process Management&#xff0c;翻译后简称BPM&#xff09;即业务流程管理系统&#xff0c;是指对端到端业务流程进行建模、分析和优化&#xff0c;以实现战略业务目标&#xff0c;其特点是注…

Elasticsearch:如何在 CentOS 上创建多节点的 Elasticsearch 集群 - 8.x

在我之前的文章 “Elasticsearch&#xff1a;使用 RPM 安装包来安装 Elastic Stack 8.x” 里&#xff0c;我详细地介绍了如何使用 RPM 安装包来安装 Elastic Stack 8.x。在今天的文章中&#xff0c;我来详细描述如何从零开始来创建一个含有三个节点的 Elasticsearch 集群。我们…

python文本处理尝试

Python文本处理尝试 最近打算看CSAPP&#xff0c;GitHub上看到有英语字幕ass源文件&#xff0c;想把字幕提取出来提高学习效率&#xff0c;先把ass文件转成txt文件&#xff0c;发现是这样&#x1f447; 都在Dialogue的后面&#xff0c;打算尝试提取一下 不太熟练&#xff0c;下…