Maison  >  Article  >  développement back-end  >  Étudier l'implémentation du verrouillage de Golang

Étudier l'implémentation du verrouillage de Golang

PHPz
PHPzoriginal
2023-12-28 10:32:43719parcourir

Étudier limplémentation du verrouillage de Golang

Exploration du mécanisme d'implémentation du verrouillage Golang

Introduction :

En programmation simultanée, le verrouillage (Lock) est un mécanisme de synchronisation couramment utilisé pour protéger l'accès aux ressources partagées. En tant que langage de programmation doté de performances de concurrence élevées et d'une syntaxe concise, Golang fournit une multitude de mécanismes de verrouillage, notamment le mutex (Mutex), le verrouillage en lecture-écriture (RWMutex), etc. Cet article approfondira le mécanisme de mise en œuvre des verrous Golang et le démontrera à travers des exemples de code spécifiques.

1. Mécanisme de mise en œuvre du verrouillage mutex (Mutex)

  1. Mise en œuvre de la méthode de verrouillage :

Le mécanisme de mise en œuvre du verrouillage mutex se compose principalement de trois composants importants : la file d'attente, l'indicateur d'état et le fonctionnement atomique. Lorsqu'un thread tente d'acquérir un verrou mutex, il vérifiera d'abord l'indicateur d'état. Si l'indicateur d'état est verrouillé, il s'ajoutera à la file d'attente et tournera pour attendre. Si l'indicateur d'état est déverrouillé, essayez d'utiliser des opérations atomiques pour acquérir le verrou et définissez l'indicateur d'état sur verrouillé. Voici un exemple de code spécifique d'un verrou mutex :

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. Implémentation d'une opération atomique :

Le code ci-dessus utilise les fonctions CompareAndSwapInt32 et StoreInt32 du package atomique pour implémenter des opérations atomiques. La fonction CompareAndSwapInt32 est utilisée pour les opérations de comparaison et d'échange. Si l'indicateur d'état du verrou est déverrouillé, il est défini sur verrouillé et renvoie vrai. Si l'indicateur d'état du verrou est verrouillé, il renvoie faux. La fonction StoreInt32 est utilisée pour définir atomiquement l'indicateur d'état sur déverrouillé. Ces opérations atomiques peuvent efficacement éviter l'apparition de conditions de concurrence et garantir l'exactitude du verrouillage.

2. Mécanisme de mise en œuvre du verrouillage en lecture-écriture (RWMutex)

  1. Mécanisme de mise en œuvre du verrouillage en écriture :

Le verrouillage en lecture-écriture est un mécanisme de verrouillage spécial qui permet à plusieurs goroutines de lire des ressources partagées en même temps, mais uniquement. Une goroutine écrit sur une ressource partagée. Le mécanisme de mise en œuvre du verrouillage en écriture est similaire à celui du verrouillage mutex, mais il existe quelques différences. Voici un exemple de code spécifique d'un verrou en lecture :

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. Mécanisme d'implémentation du verrou en lecture :

Le mécanisme d'implémentation du verrou en lecture est principalement implémenté en incrémentant le sémaphore de lecture et le nombre de lectures lorsqu'une goroutine acquiert le verrou en lecture. , il vérifiera d'abord si le sémaphore d'écriture est nul et s'il n'y a pas d'autres goroutines en attente d'écriture. Si c'est le cas, incrémentez le nombre de lectures et acquérez le verrou de lecture, sinon, ajoutez-le à la file d'attente pour l'attente de rotation. Voici un exemple de code spécifique d'un verrou en lecture :

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. Réveillez la goroutine en attente :

Dans l'implémentation du verrou en lecture-écriture, il y a une opération pour réveiller la goroutine en attente. Il est implémenté via deux fonctions auxiliaires : lockWhile et unlockWhile. La fonction lockWhile est utilisée pour l'attente de rotation Lorsque la condition donnée est vraie, la goroutine sera bloquée jusqu'à ce que la condition soit remplie ; la fonction unlockWhile est utilisée pour réveiller la goroutine en attente selon la condition donnée afin qu'elle puisse concourir pour le tour. verrouillage. Cela garantit que les goroutines en attente de verrous peuvent être réveillées à temps et améliore les performances de concurrence.

Résumé :

Dans cet article, nous avons mené une exploration approfondie du mécanisme de mise en œuvre des verrous dans Golang et l'avons démontré à travers des exemples de code spécifiques. Les verrous mutex sont implémentés via des files d'attente et des indicateurs d'état pour garantir qu'un seul goroutine peut détenir le verrou ; tandis que les verrous en lecture-écriture sont implémentés via des sémaphores d'écriture, des sémaphores de lecture et des comptes de lecture, permettant à plusieurs goroutines de lire et d'écrire en même temps. Une seule goroutine est autorisée à écrire. Ces mécanismes de verrouillage garantissent un accès sécurisé aux ressources partagées et améliorent les performances des programmes simultanés grâce à des opérations atomiques et à une attente conditionnelle.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn