>  기사  >  백엔드 개발  >  Golang의 잠금 구현 연구

Golang의 잠금 구현 연구

PHPz
PHPz원래의
2023-12-28 10:32:43665검색

Golang의 잠금 구현 연구

Golang 잠금 구현 메커니즘 살펴보기

소개:

동시 프로그래밍에서 잠금(Lock)은 공유 리소스에 대한 액세스를 보호하는 데 사용되는 일반적으로 사용되는 동기화 메커니즘입니다. 높은 동시성 성능과 간결한 구문을 갖춘 프로그래밍 언어인 Golang은 뮤텍스(Mutex), 읽기-쓰기 잠금(RWMutex) 등을 포함한 풍부한 잠금 메커니즘을 제공합니다. 이 기사에서는 Golang 잠금의 구현 메커니즘을 자세히 살펴보고 특정 코드 예제를 통해 이를 보여줍니다.

1. 뮤텍스 잠금 구현 메커니즘(Mutex)

  1. 잠금 메서드 구현:

뮤텍스 잠금 구현 메커니즘은 주로 대기 대기열, 상태 플래그 및 원자적 작업의 세 가지 중요한 구성 요소로 구성됩니다. 스레드가 뮤텍스 잠금을 획득하려고 시도하면 먼저 상태 플래그를 확인합니다. 상태 플래그가 잠겨 있으면 대기 대기열에 추가되어 대기합니다. 상태 플래그가 잠금 해제된 경우 원자성 작업을 사용하여 잠금을 획득하고 상태 플래그를 잠김으로 설정해 보세요. 다음은 뮤텍스 잠금의 특정 코드 예입니다.

type Mutex struct {
    waiting   int32 // 等待队列,记录等待获取锁的goroutine数量
    isLocked  int32 // 锁的状态标志,0代表未锁住,1代表已锁住
}

func (m *Mutex) Lock() {
    for !atomic.CompareAndSwapInt32(&m.isLocked, 0, 1) { // 自旋等待获取锁
        runtime.Gosched()
    }
}

func (m *Mutex) Unlock() {
    atomic.StoreInt32(&m.isLocked, 0) // 释放锁,将状态标志设置为未锁住
}
  1. 원자 연산 구현:

위 코드는 원자 패키지의 CompareAndSwapInt32 및 StoreInt32 함수를 사용하여 원자 연산을 구현합니다. CompareAndSwapInt32 함수는 비교 및 ​​교환 작업에 사용됩니다. 잠금 상태 플래그가 잠금 해제되면 잠김으로 설정되고 잠금 상태 플래그가 잠겨 있으면 false를 반환합니다. StoreInt32 함수는 상태 플래그를 잠금 해제로 원자적으로 설정하는 데 사용됩니다. 이러한 원자적 작업은 경쟁 조건의 발생을 효과적으로 방지하고 잠금의 정확성을 보장할 수 있습니다.

2. 읽기-쓰기 잠금 구현 메커니즘(RWMutex)

  1. 쓰기 잠금 구현 메커니즘:

읽기-쓰기 잠금은 여러 고루틴이 동시에 공유 리소스를 읽을 수 있도록 하는 특수 잠금 메커니즘입니다. 고루틴은 공유 리소스에 씁니다. 쓰기 잠금의 구현 메커니즘은 뮤텍스 잠금과 유사하지만 몇 가지 차이점이 있습니다. 다음은 쓰기 잠금의 구체적인 코드 예입니다.

type RWMutex struct {
    writerSem uint32    // 写入信号量,用于限制只能有一个goroutine写入
    readerSem uint32    // 读取信号量,用于限制多个goroutine同时读取
    readerCount int32   // 读取计数,记录当前同时读取的goroutine数量
    readerWait  int32   // 当前等待读取的goroutine数量
}

func (rw *RWMutex) Lock() {
    rw.lockWhile(func() {atomic.LoadUint32(&rw.readerSem) != 0 || atomic.LoadUint32(&rw.writerSem) != 0})
    atomic.AddUint32(&rw.writerSem, 1) // 获取写锁,递增写入信号量
}

func (rw *RWMutex) Unlock() {
    atomic.AddUint32(&rw.writerSem, ^uint32(0)) // 释放写锁,递减写入信号量
    rw.unlockWhile(func() {atomic.LoadInt32(&rw.readerCount) != 0}) // 释放读锁,根据读取计数判断是否需要唤醒等待读取的goroutine
}
  1. 읽기 잠금 구현 메커니즘:

읽기 잠금 구현 메커니즘은 주로 고루틴이 읽기 잠금을 획득할 때 읽기 세마포어와 읽기 횟수를 증가시켜 구현됩니다. , 먼저 쓰기 세마포어가 0이고 쓰기를 기다리는 다른 고루틴이 없는지 확인합니다. 그렇다면 읽기 횟수를 늘리고 읽기 잠금을 획득합니다. 그렇지 않으면 스핀 대기를 위해 대기 큐에 추가됩니다. 다음은 읽기 잠금의 구체적인 코드 예입니다.

func (rw *RWMutex) RLock() {
    rw.lockWhile(func() {atomic.LoadUint32(&rw.writerSem) != 0}) // 当有 goroutine 持有写锁时,自旋等待
    atomic.AddInt32(&rw.readerCount, 1) // 递增读取计数
}

func (rw *RWMutex) RUnlock() {
    atomic.AddInt32(&rw.readerCount, -1) // 递减读取计数
    rw.unlockWhile(func() {atomic.LoadInt32(&rw.readerCount) != 0}) // 根据读取计数判断是否需要唤醒等待读取的goroutine
}
  1. 대기 중인 고루틴을 깨우세요:

읽기-쓰기 잠금 구현에는 대기 중인 고루틴을 깨우는 작업이 있습니다. 이는 lockWhile과 UnlockWhile이라는 두 가지 보조 기능을 통해 구현됩니다. lockWhile 함수는 주어진 조건이 true일 때 조건이 충족될 때까지 고루틴을 차단합니다. UnlockWhile 함수는 주어진 조건에 따라 대기 중인 고루틴을 깨우는 데 사용됩니다. 잠그다. 이를 통해 잠금을 기다리는 고루틴이 제때에 깨어날 수 있고 동시성 성능이 향상됩니다.

요약:

이 기사에서는 Golang의 잠금 구현 메커니즘을 심층적으로 탐색하고 특정 코드 예제를 통해 시연했습니다. 뮤텍스 잠금은 대기 대기열과 상태 플래그를 통해 구현되어 단 하나의 고루틴만이 잠금을 보유할 수 있도록 하며, 읽기-쓰기 잠금은 쓰기 세마포어, 읽기 세마포어 및 읽기 횟수를 통해 구현되어 여러 고루틴이 동시에 읽고 쓸 수 있도록 합니다. 고루틴은 하나만 쓸 수 있습니다. 이러한 잠금 메커니즘은 공유 리소스에 대한 안전한 액세스를 보장하고 원자성 작업 및 조건부 대기를 통해 동시 프로그램의 성능을 향상시킵니다.

위 내용은 Golang의 잠금 구현 연구의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.