Mutex正常模式与饥饿模式

简介: 在Go中,sync包提供了一种称为Mutex(互斥锁)的机制来实现对共享资源的并发访问控制。Mutex有两种模式:正常模式和饥饿模式。

正常模式是指当有多个goroutine同时请求锁时,Mutex会公平地选择一个goroutine来获取锁,其他goroutine会被放入一个FIFO(先进先出)的等待队列中。当锁被释放时,等待队列中的goroutine会按照先后顺序获取锁。

饥饿模式是指当有多个goroutine同时请求锁时,Mutex不公平地选择一个goroutine来获取锁,而是优先选择之前请求锁但被拒绝的goroutine,而不是等待队列中的其他goroutine。这样,被拒绝的goroutine有机会尽快获取锁,避免了其他goroutine持有锁的时间过长而导致的不公平性。

通过调用Mutex的方法Lock()和Unlock()来获取和释放锁。示例如下:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
   
    var mu sync.Mutex

    for i := 0; i < 10; i++ {
   
        go func() {
   
            mu.Lock()
            defer mu.Unlock()

            fmt.Println("goroutine", i, "got the lock")
            time.Sleep(time.Second)
            fmt.Println("goroutine", i, "released the lock")
        }()
    }

    time.Sleep(5 * time.Second)
}

上面的示例中,我们创建了10个并发的goroutine,每个goroutine都会获取锁后打印一条消息,然后休眠1秒,最后释放锁。程序运行后,我们会看到goroutine的顺序是乱序的,这是因为Mutex是无序的,没有固定的顺序。

如果我们将Mutex的模式从正常模式更改为饥饿模式,可以通过修改Mutex的配置来实现。例如:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)

type starvingMutex struct {
   
    sync.Mutex
}

func (m *starvingMutex) Lock() {
   
    atomic.StoreInt32((*int32)(&m.Mutex), 1)
    m.Mutex.Lock()
}

func (m *starvingMutex) Unlock() {
   
    m.Mutex.Unlock()
    atomic.StoreInt32((*int32)(&m.Mutex), 0)
}

func main() {
   
    var mu starvingMutex

    for i := 0; i < 10; i++ {
   
        go func() {
   
            mu.Lock()
            defer mu.Unlock()

            fmt.Println("goroutine", i, "got the lock")
            time.Sleep(time.Second)
            fmt.Println("goroutine", i, "released the lock")
        }()
    }

    time.Sleep(5 * time.Second)
}

上面的示例中,我们自定义了一个starvingMutex类型,内嵌了sync.Mutex,并重写了Lock()和Unlock()方法。在Lock()方法中,我们先通过atomic.StoreInt32方法将Mutex的状态设置为1,然后再调用Mutex的Lock()方法。这样,之前请求锁但被拒绝的goroutine就有机会尽快获取锁。

注意,饥饿模式可能会导致更多的锁竞争和额外的性能开销,因此在大多数情况下,默认使用正常模式即可。只有在特定场景下才考虑切换到饥饿模式。

目录
相关文章
|
1月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
6月前
|
安全 算法 Linux
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(下)
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(下)
|
6月前
|
缓存 Linux 调度
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(上)
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(上)
|
6月前
|
存储 Linux 程序员
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(中)
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(中)
|
6月前
|
安全 算法 Linux
Linux多线程【线程互斥与同步】
Linux多线程【线程互斥与同步】
89 0
|
6月前
|
Linux 数据安全/隐私保护
Linux线程同步(条件变量)
Linux线程同步(条件变量)
82 0
StampedLock 支持的三种锁模式
StampedLock 支持的三种锁模式
43 1
互斥信号+任务临界创建+任务锁
互斥信号+任务临界创建+任务锁
|
安全 Linux 数据安全/隐私保护
Linux线程同步与互斥(一)
着重讲解Linux线程的互斥!
Linux线程同步与互斥(一)
|
Linux API
【Linux线程同步专题】二、读写锁
【Linux线程同步专题】二、读写锁
187 0