1
votes

Comment débloquer Mutex deux fois

Est-il sécuritaire de déverrouiller un mutex deux fois? Mon code:

var m sync.RWMutex = sync.RWMutex{}

func Read() {
    m.RLock()
    defer m.RUnlock()

    // Do something that needs lock
    err := SomeFunction1()
    if err != nil {
        return
    }

    m.RUnlock()

    // Do something that does not need lock
    SomeFunction2()

}

J'ai besoin de différer m.RUnlock () pour le cas SomeFunction1 () renvoie une erreur. Mais lorsque SomeFunction1 () revient sans erreur, m sera déverrouillé deux fois par m.RUnlock () et différer m.RUnlock ( ) .

Est-il sûr de déverrouiller le mutex deux fois? Sinon, comment dois-je corriger mon code?

go

1 commentaires

Notez que lorsque vous avez envie de faire cela (verrouiller et déverrouiller un mutex à divers points étranges d'une fonction), c'est généralement un signe que votre code n'est pas vraiment correctement structuré. Il y a cependant des cas étranges où cela est approprié.


3 Réponses :


0
votes

Le déverrouillage d'un Mutex déverrouillé provoquera une panique.

Vous pouvez simplement supprimer le différer et l'ajouter dans la condition if:

func Read() {
    m.RLock()

    err := SomeFunction1()
    m.RUnlock()
    if (err != nil) {
        return
    }

    SomeFunction2()
}

Ou encore mieux (avec un impact mineur sur la lisibilité):

var m sync.RWMutex = sync.RWMutex{}

func Read() {
    m.RLock()

    // Do something that needs lock
    err := SomeFunction1()
    if (err != nil) {
        m.RUnlock()
        return
    }

    m.RUnlock()

    // Do something that does not need lock
    SomeFunction2()
}


0 commentaires

1
votes

De godoc:

Alors, ne faites pas cela.

La solution la plus simple est de ne pas utiliser le déverrouillage différé, mais de le déverrouiller à chaque sortie possible. Ou, vous pouvez aussi faire ceci, mais ce n'est pas facile à lire:

func Read() {
    if err := func() {
      m.RLock()
      defer m.RUnlock()

      // Do something that needs lock
      err := SomeFunction1()
      if err != nil {
          return err
      }(); err != nil {
        return err
     }

    // Do something that does not need lock
    SomeFunction2()

}


0 commentaires

2
votes

Est-il sûr de déverrouiller un mutex deux fois?

Non, vous ne devriez pas déverrouiller le mutex deux fois. Il s'agit d'une erreur d'exécution selon la documentation .

RUnlock annule un seul appel RLock; il n'affecte pas les autres lecteurs simultanés. C'est une erreur d'exécution si rw n'est pas verrouillé pour la lecture à l'entrée de RUnlock.


Sinon, comment dois-je corriger mon code?

Je recommanderais de conserver le différer mais uniquement m.RUnlock () en cas d'erreur. Cela peut facilement évoluer au cas où vous ajouteriez plus d'appels de fonction entre SomeFunction1 () et SomeFunction2().

func Read() {
    var err error
    m.RLock()
    defer func() {
        if err != nil {
            m.RUnlock()
        }
    }()
    

    // Do something that needs lock
    err = SomeFunction1()
    if err != nil {
        return
    }

    m.RUnlock()

    // Do something that does not need lock
    SomeFunction2()
}

Essayez sur Go Playground !


0 commentaires