返回顶部
首页 > 资讯 > 后端开发 > GO >Golang中的Mutex怎么使用
  • 101
分享到

Golang中的Mutex怎么使用

2023-07-05 17:07:33 101人浏览 薄情痞子
摘要

本篇内容介绍了“golang中的Mutex怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Mutex基本概念Mutex 是 Go 语言

本篇内容介绍了“golang中的Mutex怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

    Mutex

    基本概念

    MutexGo 语言中互斥的实现,它是一种同步机制,用于控制多个 goroutine 之间的并发访问。当多个 goroutine 尝试同时访问同一个共享资源时,可能会导致数据竞争和其他并发问题,因此需要使用互斥锁来协调它们之间的访问。

    Golang中的Mutex怎么使用

    在上述图片中,我们可以将绿色部分看作是临界区。当 g1 协程通过 mutex 对临界区进行加锁后,临界区将会被锁定。此时如果 g2 想要访问临界区,就会失败并进入阻塞状态,直到锁被释放,g2 才能拿到临界区的访问权。

    结构体介绍

    type Mutex struct {    state int32    sema  uint32}

    字段:

    state

    state 是一个 int32 类型的变量,它存储着 Mutex 的各种状态信息(未加锁、被加锁、唤醒状态、饥饿状态),不同状态通过位运算进行计算。

    sema

    sema 是一个信号量,用于实现 Mutex 的等待和唤醒机制。

    方法:

    Lock()

    Lock() 方法用于获取 Mutex 的锁,如果 Mutex 已经被其他的 goroutine 锁定,则 Lock() 方法会一直阻塞,直到该 goroutine 获取到锁为止。

    UnLock()

    Unlock() 方法用于释放 Mutex 的锁,将 Mutex 的状态设置为未锁定的状态。

    TryLock()

    Go 1.18 版本以后,sync.Mutex 新增一个 TryLock() 方法,该方法为非阻塞式的加锁操作,如果加锁成功,返回 true,否则返回 false

    虽然 TryLock() 的用法确实存在,但由于其使用场景相对较少,因此在使用时应该格外谨慎。TryLock() 方法注释如下所示:

    // Note that while correct uses of TryLock do exist, they are rare,// and use of TryLock is often a sign of a deeper problem// in a particular use of mutexes.

    代码示例

    我们先来看一个有并发安全问题的例子

    package mainimport (   "fmt"   "sync")var cnt intfunc main() {   var wg sync.WaitGroup   for i := 0; i < 10; i++ {      wg.Add(1)      go func() {         defer wg.Done()         for j := 0; j < 10000; j++ {            cnt++         }      }()   }   wg.Wait()   fmt.Println(cnt)}

    在这个例子中,预期的 cnt 结果为 10 * 10000 = 100000。但是由于多个 goroutine 并发访问了共享变量 cnt,并且没有进行任何同步操作,可能导致读写冲突(race condition),从而影响 cnt 的值和输出结果的正确性。这种情况下,不能确定最终输出的 cnt 值是多少,每次执行程序得到的结果可能不同。

    在这种情况下,可以使用互斥锁(sync.Mutex)来保护共享变量的访问,保证只有一个 goroutine 能够同时访问 cnt,从而避免竞态条件的问题。修改后的代码如下:

    package mainimport (   "fmt"   "sync")var cnt intvar mu sync.Mutexfunc main() {   var wg sync.WaitGroup   for i := 0; i < 10; i++ {      wg.Add(1)      go func() {         defer wg.Done()         for j := 0; j < 10000; j++ {            mu.Lock()            cnt++            mu.Unlock()         }      }()   }   wg.Wait()   fmt.Println(cnt)}

    在这个修改后的版本中,使用互斥锁来保护共享变量 cnt 的访问,可以避免出现竞态条件的问题。具体而言,在 cnt++ 操作前,先执行 Lock() 方法,以确保当前 goroutine 获取到了互斥锁并且独占了共享变量的访问权。在 cnt++ 操作完成后,再执行 Unlock() 方法来释放互斥锁,从而允许其他 goroutine 获取互斥锁并访问共享变量。这样,只有一个 goroutine 能够同时访问 cnt,从而确保了最终输出结果的正确性。

    易错场景

    忘记解锁

    如果使用 Lock() 方法之后,没有调用 Unlock() 解锁,会导致其他 goroutine 被永久阻塞。例如:

    package mainimport (   "fmt"   "sync"   "time")var mu sync.Mutexvar cnt intfunc main() {   go increase(1)   go increase(2)   time.Sleep(time.Second)   fmt.Println(cnt)}func increase(delta int) {   mu.Lock()   cnt += delta}

    在上述代码中,通常情况下,cnt 的结果应该为 3。然而没有解锁操作,其中一个 goroutine 被阻塞,导致没有达到预期效果,最终输出的 cnt 可能只能为 12

    正确的做法是使用 defer 语句在函数返回前释放锁。

    func increase(delta int) {   mu.Lock()   defer mu.Unlock() // 通过 defer 语句在函数返回前释放锁   cnt += delta}

    重复加锁

    重复加锁操作被称为可重入操作。不同于其他一些编程语言的锁实现(例如 JavaReentrantLock),Gomutex 并不支持可重入操作,如果发生了重复加锁操作,就会导致死锁。例如:

    package mainimport (   "fmt"   "sync"   "time")var mu sync.Mutexvar cnt intfunc main() {   go increase(1)   go increase(2)   time.Sleep(time.Second)   fmt.Println(cnt)}func increase(delta int) {   mu.Lock()   mu.Lock()   cnt += delta   mu.Unlock()}

    在这个例子中,如果在 increase 函数中重复加锁,将会导致 mu 锁被第二次锁住,而其他 goroutine 将被永久阻塞,从而导致程序死锁。正确的做法是只对需要加锁的代码段进行加锁,避免重复加锁。

    基于 Mutex 实现一个简单的线程安全的缓存

    import "sync"type Cache struct {   data map[string]any   mu   sync.Mutex}func (c *Cache) Get(key string) (any, bool) {   c.mu.Lock()   defer c.mu.Unlock()   value, ok := c.data[key]   return value, ok}func (c *Cache) Set(key string, value any) {   c.mu.Lock()   defer c.mu.Unlock()   c.data[key] = value}

    上述代码实现了一个简单的线程安全的缓存。使用 Mutex 可以保证同一时刻只有一个 goroutine 进行读写操作,避免多个 goroutine 并发读写同一数据时产生数据不一致性的问题。

    对于缓存场景,读操作比写操作更频繁,因此使用 RWMutex 代替 Mutex 会更好,因为 RWMutex 允许多个 goroutine 同时进行读操作,只有在写操作时才会进行互斥锁定,从而减少了锁的竞争,提高了程序的并发性能。

    “Golang中的Mutex怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

    您可能感兴趣的文档:

    --结束END--

    本文标题: Golang中的Mutex怎么使用

    本文链接: https://lsjlt.com/news/353669.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Golang中的Mutex怎么使用
      本篇内容介绍了“Golang中的Mutex怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Mutex基本概念Mutex 是 Go 语言...
      99+
      2023-07-05
    • 初识Golang Mutex互斥锁的使用
      目录前言为什么要使用互斥锁如何使用互斥锁使用方式一:直接声明使用使用方式二:封装在其他结构体中互斥锁的常见问题前言 在学习操作系统的时候,我们应该都学习过临界区、互斥锁这些概念,用于...
      99+
      2024-04-02
    • C# Mutex对象怎么使用
      本篇内容主要讲解“C# Mutex对象怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C# Mutex对象怎么使用”吧!如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对...
      99+
      2023-06-17
    • c++的mutex怎么用
      本篇内容介绍了“c++的mutex怎么用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!面临的问题多线程同时操作一段数据时,线程调度由操作系统...
      99+
      2023-06-19
    • golang pprof监控memory block mutex使用指南
      目录profiletrace 网页显示如何使用http 接口暴露的方式allocs ,heapblockmutex代码生成profile文件的方式总结profile profile...
      99+
      2023-05-14
      golang pprof监控 go memory block mutex
    • golang pprof监控memory block mutex使用的方法是什么
      这篇文章主要介绍“golang pprof监控memory block mutex使用的方法是什么”,在日常操作中,相信很多人在golang pprof监控memory block ...
      99+
      2023-07-05
    • GoLang中的互斥锁Mutex和读写锁RWMutex使用教程
      目录一、竞态条件与临界区和同步工具(1)竞态条件(2)临界区(3)同步工具二、互斥量三、使用互斥锁的注意事项(1)使用互斥锁的注意事项(2)使用defer语句解锁(3)sync.Mu...
      99+
      2023-01-09
      Go Mutex和RWMutex Go Mutex GoLang RWMutex
    • c#的互斥锁Mutex类怎么使用
      本篇内容主要讲解“c#的互斥锁Mutex类怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“c#的互斥锁Mutex类怎么使用”吧!什么是Mutex“mutex”是术语“互相排斥(mutual...
      99+
      2023-06-29
    • golang中的.()怎么使用
      这篇文章主要介绍“golang中的.()怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“golang中的.()怎么使用”文章能帮助大家解决问题。什么是.()用法?在golang中,.()被称为...
      99+
      2023-07-05
    • C#多线程中的互斥锁Mutex怎么用
      本篇内容主要讲解“C#多线程中的互斥锁Mutex怎么用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#多线程中的互斥锁Mutex怎么用”吧!一、简介Mutex的突出特点是可以跨应用程序域边界对...
      99+
      2023-06-30
    • Linux中如何使用互斥量mutex
      小编给大家分享一下Linux中如何使用互斥量mutex,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!##互斥量mutex前文提到,系统中如果存在资源共享,线程间存...
      99+
      2023-06-15
    • Golang中的interface怎么使用
      这篇文章主要讲解了“Golang中的interface怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang中的interface怎么使用”吧!万能类型interface在Jav...
      99+
      2023-06-27
    • Golang中的sync.Map怎么使用
      今天小编给大家分享一下Golang中的sync.Map怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。map 在并发下...
      99+
      2023-07-05
    • Golang中的RWMutex怎么使用
      本篇内容主要讲解“Golang中的RWMutex怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang中的RWMutex怎么使用”吧!RWMutex 的整体模型正如 RWMutex ...
      99+
      2023-07-05
    • Golang中的WaitGroups怎么使用
      本篇内容介绍了“Golang中的WaitGroups怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么是WaitGroupsWait...
      99+
      2023-07-05
    • Golang中的sync.Cond怎么使用
      本文小编为大家详细介绍“Golang中的sync.Cond怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Golang中的sync.Cond怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. 基本...
      99+
      2023-07-05
    • golang中的注释怎么使用
      本篇内容主要讲解“golang中的注释怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“golang中的注释怎么使用”吧!一、单行注释单行注释是在代码行的末尾添加注释的方式,以“//”开头。...
      99+
      2023-07-05
    • golang中怎么使用gopath
      小编给大家分享一下golang中怎么使用gopath,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!golang gopath的新用法从使用golang开发项目以来...
      99+
      2023-06-14
    • golang中channel怎么使用
      今天小编给大家分享一下golang中channel怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。什么是 channe...
      99+
      2023-06-29
    • golang中defer怎么使用
      这篇文章主要介绍“golang中defer怎么使用”,在日常操作中,相信很多人在golang中defer怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”golang中defer怎么使用”的疑惑有所帮助!...
      99+
      2023-07-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作