Go语言互斥锁

幸运草
幸运草
幸运草
1033
文章
3
评论
2020年4月23日22:01:26
评论
146

Go语言互斥锁

Go语言的sync包中实现了两种锁 Mutex (互斥锁)和 RWMutex (读写锁),其中 RWMutex 是基于 Mutex 实现的,只读锁的实现使用类似引用计数器的功能。

互斥锁

Mutex 是互斥锁,有 Lock()加锁、Unlock()解锁两个方法,使用Lock()加锁后,便不能再次对其进行加锁,直到利用 Unlock()解锁对其解锁后才能再次加锁。适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁也叫做全局锁。

func (m *Mutex) Lock()

Lock方法锁住m,如果m已经加锁,则阻塞直到m解锁。

func (m *Mutex) Unlock()

Unlock方法解锁m,如果m未加锁会导致运行时错误。锁和线程无关,可以由不同的线程加锁和解锁。

互斥锁应用

只要有两个goroutine并发访问同一变量,且至少其中的一个是写操作的时候就会发生数据竞争。数据竞争会在两个以上的goroutine并发访问相同的变量且至少其中一个为写操作时发生。

允许多个goroutine访问变量,但是同一时间只允许一个goroutine访问。我们可以用sync包中的Mutex来实现,保证共享变量不会被并发访问。

实例如下:

package main

import (
    "fmt"
    "sync"
)

var (
    m     = make(map[int]int)
    Mlock = new(sync.Mutex)
)

func main() {
    for i := 0; i < 1000; i++ {
        go func(i int) {
            // Mlock.Lock()
            m[i] = i * i
            // Mlock.Unlock()
        }(i)
    }

    // Mlock.Lock()
    for k, v := range m {
        fmt.Printf("%d * %d = %dn", k, k, v)
    }
    // Mlock.Unlock()
}

运行错误:

fatal error: concurrent map writes

将上述代码中的注释打开则程序正常运行。

当Unlock()在Lock()之前使用时便会报错,实例如下:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var MLock *sync.Mutex
    MLock = new(sync.Mutex)
    MLock.Unlock()
    fmt.Println("hello Mutex")
    MLock.Lock()
}

运行错误:

panic: sync: unlock of unlocked mutex

当在解锁之前再次进行加锁,便会死锁状态,实例如下:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var MLock *sync.Mutex
    MLock = new(sync.Mutex)
    MLock.Lock()
    fmt.Println("hello Mutex")
    MLock.Lock()
}

运行错误:

fatal error: all goroutines are asleep - deadlock!

互斥锁只能锁定一次,当在解锁之前再次进行加锁,便会死锁状态,如果在加锁前解锁,便会报错“panic: sync: unlock of unlocked mutex”。

特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

转载请注明:{{title}}-变化吧
  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 赞助本站
  • 支付宝扫一扫
  • weinxin
幸运草
Go语言中的常量 函数代码

Go语言中的常量

1 概述 常量,一经定义不可更改的量。功能角度看,当出现不需要被更改的数据时,应该使用常量进行存储,例如圆周率。从语法的角度看,使用常量可以保证数据,在整个运行期间内,不会被更改。例如当前处理器的架构...
Go语言的接口 函数代码

Go语言的接口

Go语言-接口 在Go语言中,一个接口类型总是代表着某一种类型(即所有实现它的类型)的行为。一个接口类型的声明通常会包含关键字type、类型名称、关键字interface以及由花括号包裹的若干方法声明...
Go语言支持的正则语法 函数代码

Go语言支持的正则语法

1 字符 语法 说明 . 任意字符,在单行模式(s标志)下,也可以匹配换行 字符类 否定字符类 d Perl 字符类 D 否定 Perl 字符类 ASCII 字符类 否定 ASCII 字符类 pN U...
Go语言的包管理 函数代码

Go语言的包管理

1 概述 Go 语言的源码复用建立在包(package)基础之上。包通过 package, import, GOPATH 操作完成。 2 main包 Go 语言的入口 main() 函数所在的包(pa...