2017-06-17 5 views
-1

Als Anfänger von golang sperren verwenden, finde ich die Mutex von golang ist nicht wieder entranceLock aus dem Buch The Go Programming Language. Und sie erklären den Grund als:, wenn wir nicht wieder Eingang

Es gibt einen guten Grund Go's Mutexe sind nicht einspringend. Der Zweck eines Mutex ist es, sicherzustellen, dass bestimmte Invarianten der geteilten Variablen an kritischen Punkten während der Programmausführung beibehalten werden. Eine der Invarianten ist "keine Goroutine greift auf die geteilten Variablen zu", aber es kann zusätzliche Invarianten geben, die für die Datenstrukturen spezifisch sind, die der Mutex schützt. Wenn eine Goroutine eine Mutex-Sperre erwirbt, kann sie annehmen, dass die Invarianten bestehen. Während es die Sperre enthält, kann es die freigegebenen Variablen aktualisieren, so dass die Invarianten vorübergehend verletzt werden. Wenn jedoch die Sperre aufgehoben wird, muss sie sicherstellen, dass die Reihenfolge wiederhergestellt wurde und die Invarianten erneut gehalten werden. Obwohl ein Re-entrant-Mutex sicherstellen würde, dass keine anderen Grouutinen auf die gemeinsam genutzten Variablen zugreifen, kann er die zusätzlichen Invarianten dieser Variablen nicht schützen.

es schien die Erklärung ist Detail genug, leider kann ich es nicht bekommen. Ich weiß immer noch nicht, wann wir nicht Re-EntranceLock verwenden sollten, und wenn nicht, welche schlechte Überraschung werde ich erhalten? Ich werde es schätzen, wenn mir jemand ein Beispiel geben kann.

Antwort

0

Hier ist ein Beispiel von schlecht Code nur um das Problem zu veranschaulichen:

package main 

import (
    "fmt" 
    "sync" 
) 

type SafeCounter struct { 
    lock  sync.Mutex 
    count  int 
    enabled bool 
    NextValue func(int) int 
} 

const maxCount = 10 

func (c *SafeCounter) Count() int { 
    return c.count 
} 

func (c *SafeCounter) Increment() { 
    c.lock.Lock() 
    if c.enabled { 
     c.count = c.NextValue(c.count) 
    } 
    c.lock.Unlock() 
} 

func (c *SafeCounter) SetEnabled(enabled bool) { 
    c.lock.Lock() 
    c.enabled = enabled 
    if !enabled { 
     c.count = 0 
    } 
    c.lock.Unlock() 
} 

func main() { 
    var counter SafeCounter 
    counter.SetEnabled(true) 
    counter.NextValue = func(value int) int { 
     if counter.Count() > maxCount { 
      // Safe counter doesn't expect this here! 
      // The program will panic in SetEnabled 
      counter.SetEnabled(false) 
     } 
     return value + 1 
    } 
    for i := 0; i < 100; i++ { 
     doAction() 
     counter.Increment() 
    } 
    fmt.Println(counter.Count()) 
} 

func doAction() { 
    // some action 
} 

Beide Increment und SetEnabled acquire Schlösser, weil sie die Werte von enabled können nicht zulassen, und count zu ändern, während sie sind in die Mitte von etwas. Wenn die Sperre jedoch reentrant (rekursiv) wäre, wäre sie zulässig (da beide Aufrufe mit derselben Goroutine ausgeführt werden).

Verwandte Themen