当前位置: 首页 > news >正文

【Go专家编程——并发控制——Mutex】

1.Mutex

互斥锁是并发程序中对共享资源进行访问控制的主要手段,对此Go语言提供了Mutex,对外暴露Lock()和Unlock两个方法,分别用于加锁和解锁。

1.1 Mutex的数据结构

源码如下:

type Mutex struct{state int32//代表互斥锁的状态sema uint32//表示信号量,协程阻塞等待该信号量。解锁的协程释放信号量从而唤醒等待信号量的协程
}

state表面上看起来是32位的整型变量,实际上内部分成了4部分。
在这里插入图片描述

  • Locked:表示该Mutex是否已被锁定,0表示没有锁定,1表示已被锁定
  • Woken:表示是否有协程已被唤醒,0表示没有协程唤醒,1表示已有协程唤醒,正在加锁过程中
  • Starving:表示该Mutex是否处于饥饿状态,0表示没有饥饿,1表示饥饿状态,说明有协程阻塞了超过1ms
  • Waiter:表示阻塞等待锁的协程个数,协程解锁时根据此值来判断是否需要释放信号量

抢锁实际上是抢给Locked赋值的权利,抢不到就阻塞等待信号量sema,一旦持有锁的协程解锁,等待的协程就会依次被唤醒。

1.2 加/解锁过程

  • 简单加锁
    • locked置为1即可
  • 加锁被阻塞
    • waiter+1
  • 简单解锁
    • locked置为0即可
  • 解锁并唤醒协程
    • locked置为0
    • 查看waiter>0
    • 释放一个信号量,唤醒一个阻塞的协程
    • 被唤醒的协程吧locked置为1

1.3 自旋过程

加锁时,如果当前Locked位为1,尝试加锁的协程不是马上转入阻塞,而是会持续地探测Locked位是否变为0,这个过程为自旋过程。

自旋时间很短,如果在自旋过程中发现锁已被释放,那么协程可以立即获取锁。此时即便有协程被唤醒也无法获取锁,只能再次阻塞(像极了被插队的情况)

1.3.1 什么是自旋

自旋对应于CPU的PAUSE指令,CPU对该指令什么也不做,相当于CPU空转,对于程序来说相当于”sleep“了一小段时间,时间很短,30个时针周期。不同于sleep,自旋不会将协程转换为睡眠状态。

1.3.2 自旋条件

加锁时程序会自动判断是否可以自旋,无限制的自旋会给CPU带来巨大压力,所以判断是否可以自旋就很重要了。
自旋必须满足以下所有的条件:

  • 自旋次数要足够小,通常为4
  • CPU核数要大于1,否则自旋没有意义
  • 协程调度机制中的Processor数量要大于1
  • 协程调度机制中的可运行队列必须为空,否则会延迟协程调用

自旋的条件很苛刻,总而言之就是不忙的时候才会启动自旋。

1.3.3 自旋的优势

自旋的优势就是更充分地利用CPU,尽量避免协程切换。经过短时间的自旋可以获得锁,就不必进入阻塞状态。

1.3.4 自旋的问题

如果自旋过程中获得锁,那么之前被阻塞的协程将无法获得锁。如果加锁的协程特别多,每次都通过自旋获得锁,那么之前被阻塞的进程将很难获得锁,从而进入了Starving状态。

1.4 Mutex模式

1.4.1 Normal模式

在该模式下,如果协程加锁不成功不会立即转入阻塞队列,而是先判断是否满足自旋状态,如果满足则会启动自旋过程,尝试加锁。

1.4.2 Starving模式(饥饿模式)

被唤醒的协程尝试加锁时发现已经被抢占了,只好再次阻塞,不过阻塞前会判断上一次阻塞距离这次阻塞的时长,如果超过1ms,则会将Mutex标记为Starving模式,然后阻塞。

在Starving模式下,不会启动自旋。

1.5 Woken状态

加锁的程序在自旋的过程中会把woken标记为1,用于通知解锁协程不需要释放信号量。

1.6 为什么重复解锁要触发panic

如果多次Unlock(),那么可能每次都释放一个信号量,这样会唤醒多个协程,多个协程被唤醒后会继续在Lock()的逻辑中抢锁,会增加Lock()实现的复杂度,也会引起不必要的协程切换。

1.7 编程Tips

  • 使用defer避免死锁
    • 加锁后立即使用defer对其解锁,可以有效避免死锁
  • 加锁和解锁应该成对出现
    • 加锁和解锁最好出现在同一层次的代码块中

2. RWMutex

读写互斥锁,在读取数据频率远远大于写数据频率的场景会有更好的性能。

需要解决的问题:

  • 写锁阻塞写锁
  • 写锁阻塞读锁
  • 读锁阻塞写锁
  • 读锁不阻塞读锁

2.1 读写锁的数据结构

2.1.1 数据结构

源码:

type RWMutex struct{w		Mutex		//用于控制多个写锁,获得写锁首先要获取该锁writerSem	uint32	//写阻塞等待的信号量,最后一个读者释放锁时会释放信号量readerSem	uint32	//读阻塞的协程等待的信号量,持有写锁的协程释放锁后会释放信号量readerCount	int32	//记录读者个数readerWait	int32	//记录写阻塞时读者个数
}

2.1.2 接口的定义

RWMutex提供了以下几个简单的接口:

  • RLock():读锁定
    • 增加读操作计数,readerCount++
    • 阻塞等待写操作结束(如果有)
  • RUnlock():解除读锁定
    • 减少读操作计数,readerCount–
    • 最后一个解除读锁定的协程唤醒等待写操作的协程(如果有)
  • Lock():写锁定
    • 获取互斥锁
    • 阻塞等待所有读操作结束
  • Unlock():解除写锁定
    • 唤醒因读锁定而被阻塞的协程(如果有)
    • 解除互斥锁
  • TryLock():以非阻塞方式尝试写锁定
  • TryRLock():以非阻塞方式尝试读锁定

2.2 场景分析

写操作需要等待读操作结束,写操作等待期间可能还有新的读操作持续到来。但在RWMutex中为什么写锁定不会被“饿死”?

  • 因为写操作到来时,会把RWMutex.readerCount值拷贝到RWMutex.readerWait中,用于标记排在写操作前面的读者个数。
  • 写操作结束后,会递减readerWait,这个值为0时唤醒写操作。

相关文章:

【Go专家编程——并发控制——Mutex】

1.Mutex 互斥锁是并发程序中对共享资源进行访问控制的主要手段,对此Go语言提供了Mutex,对外暴露Lock()和Unlock两个方法,分别用于加锁和解锁。 1.1 Mutex的数据结构 源码如下: type Mutex struct{state int32//代表互斥锁的状…...

SRE视角下的DevOps构建之道

引言: 随着数字化时代的飞速发展,软件成为了企业竞争力的核心。为了更高效地交付高质量的软件,DevOps(Development和Operations的组合)作为一种文化、实践和工具集的集合,逐渐成为了行业内的热门话题。然而…...

小白如何如何理解滑动窗口最大值问题python

文章目录 题目描述思路什么时候弹出元素什么时候加入元素 代码示例和解释 题目描述 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 举例: 输…...

Linux--进程间通信(2)(有名管道)

目录 1.原理 2.创建命名管道 3.使用命名通道实现简单的通信 4.使用创建的命名管道 1.原理 匿名管道没有名称,它们是通过句柄在父进程和子进程之间传递的。这意味着匿名管道只能用于具有父子关系的进程之间。 但如果程序之间没关系,那么这时候就要用…...

window自动启动bat文件

开机自动开启远程桌面, WinR 执行netplwiz 命令进入设置;取消勾选,可选择所需用户,点击应用,输入远程的密码即可 开机自动开启远程桌面, WinR 执行netplwiz 命令进入设置;取消勾选&#xff0…...

2024年蓝桥杯Web开发【大赛大纲】15届

一、 组别 Web应用开发分为:大学组和职业院校组。 每位选手只能申请参加其中一个组别的竞赛。各个组别单独评奖。 研究生和本科生只能报大学组。 其它高职高专院校可自行选择报任意组别。 二. 竞赛赛程 省赛时长:4小时。 决赛时长:4小…...

【vue-cli搭建vue项目的过程2.x】

vue-cli搭建vue项目 vue-cli搭建vue项目安装node安装vue-cli脚手架并创建项目安装 Ant Design Vue或element-ui(笔者使用Ant-design-vue组件,并全局引入)开发安装三方库包1、Package.json文件---引入如下package.json文件执行npm i或npm install命令即可下载如下依赖…...

Android 生成正式版密钥库 KeyStore

步骤1:打开生成正式版密钥库设置 点击 Build 菜单,选择 Generate Signed App Bundle or APK: 这是打开后的样子: 步骤2:选择 APK Android App Bundle 是用于上架 Google Play 商店的。 正常情况下选择 APK。 选择…...

POLARDB:新零售用户MySQL上云最佳选择

什么是云数据库POLARDB? POLARDB是阿里云自主研发的最新一代RDS关系型数据库,是特别针对互联网场景设计的Cloud-Native 云原生数据库。POLARDB for MySQL版本,在提供100%兼容MySQL5.6/8.0的关系型事务处理ACID特性之上,能够提供完…...

PHP MySQL图解学习指南:开启Web开发新篇章

PHP曾经是最流行的Web开发语言,许多世界领先的网站(如Facebook、维基百科和WordPress)都是用它编写的。PHP运行在Web服务器端,通过使用存储在MySQL数据库中的数据,使得网站可以为每一位访问者显示不同的定制页面。书中采用简单、直观的图示化…...

uniapp一些问题解决

1.按钮边框如何去除? 参考博主:微信小程序按钮去不掉边框_微信小程序button去掉边框-CSDN博客文章浏览阅读1k次。最近在学uni-app,顺便自己写个小程序。左上角放了个button,可边框怎么也去不掉…原来微信小程序的按钮要去掉边框要…...

数字经济讲师培训师教授唐兴通谈新质生产力数字化转型高质量发展AI人工智能大模型大数据经信委大数据管理局

什么是数字经济? 数字经济是指通过数字技术将个人、企业、设备、数据和运营连接起来而产生的经济活动。它涵盖了互联网、移动技术、大数据和信息通信技术等多个行业和技术之间的在线连接和交易。 数字经济不同于传统经济,因为它依赖数字技术、在线交易…...

关于APM32F407配置串口DMA收发没有数据的问题记录

一.问题环境 ​ 整活了一套APM32F407的板子,用了APM32F4xx_SDK_V1.4的标准外设库,正在搭建移植底层BSP框架串口部分,BSP底层配置逻辑是从STM32F407移植过来的。DMA发送时才使能通道及配置外设地址及缓存大小。 ​ 串口1DMA配置过程如下&…...

基于python实现的深度学习web多格式纠错系统

基于python实现的深度学习web多格式纠错系统 开发语言:Python 数据库:MySQL所用到的知识:Django框架工具:pycharm、Navicat、Maven 系统功能实现 用户登录 登录功能是本系统一个非常重要的功能,这极大的保护了系统的安全。登录…...

UE5文件操作

首先在虚幻引擎中创建UMyBlueprintFunctionLibrary类,可以在该类中写我们重复利用的功能,并且这些功能不依赖于特定的游戏对象,方便全局调用。 1.文件的读取和写入 UFUNCTION(BlueprintCallable, Category "File")static bool lo…...

element plus 去掉select选择框的边框,并修改右侧图标

1.去掉选择框边框 ::v-deep .el-select__wrapper{ box-shadow: none; } ::v-deep .is-hovering{ box-shadow: none !important; }2.修改选择框右侧图标 新建CaretBottom.vue文件内容&#xff1a; <template><el-icon><CaretBottom /></el-icon> <…...

Ceph KernelFuse GetSet Quota

Kernel fuse set示例...

JVM学习-字节码指令集(二)

对象的创建与访问指令 创建指令 虽然类实例和数组都是对象&#xff0c;但Java虚拟机对类实例和数组的创建和操作使用了不同的字节码指令创建类实例指令&#xff1a;new 它接收一个操作数&#xff0c;指向常量池的索引&#xff0c;表示要创建的类型&#xff0c;执行完成后&am…...

解密网络流量监控:优化IT运维的利器

引言&#xff1a; 在当今数字化时代&#xff0c;网络流量监控是维护网络稳定与业务连续性的关键。作为一名资深网络工程师&#xff0c;我将分享一些关于网络流量监控的重要知识&#xff0c;并探讨如何在IT运维中运用这一工具优化网络性能&#xff0c;确保业务的顺畅进行。 1. 网…...

oracle 分区表常用语句(2)

给分区表增加分区 第一种不存在MAXVALUE(直接添加即可&#xff09; ALTER TABLE T6 ADD PARTITION P5 VALUES LESS THAN(TO_DATE( 2018-08-01 00:00:00, SYYYY-MM-DD HH24:MI:SS, NLS_CALENDARGREGORIAN));第二种存在MAXVALUE alter table T6 split PARTITION P4 at(TO_DAT…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...