2017-03-07 2 views
2

Ich versuche, einen Fehler zu finden, der mit den Multithreading-Anwendungen in Verbindung stehen könnte. Ich habe den Code vereinfacht:Sperr- und Ref-Werte von externer Funktion

class Outer { 
    private static int count; 

    //this function is called from multiple threads in quick succession 
    public void DoFoo() { 
    Inner.Increment(ref count); 
    } 
} 

class Inner { 
    private readonly static object mLock = new object(); 
    public static string Increment(ref count) { 
    lock (mLock) (
     if (count > 1000) 
     count = 0; 
     count++; 
    } 
    return count.ToString(); 
    } 
} 

Kann die Verriegelung garantieren die Sicherheit einer Variablen auf diese Weise weitergegeben? Gibt es irgendwelche Kopien der Zählung, die nicht offensichtlich sind und die Speichersicherheit beeinträchtigen könnten? Ich dachte, es könnte einen neuen int zurückgeben und die Zuweisung am Ende der Methode oder so machen. Abgesehen davon verstehe ich, dass der Sperrbereich alle Caching-Probleme behandeln würde.

Der Fehler, der das Problem unserer Aufmerksamkeit erregte, war scheinbar einer der Threads mit einer veralteten Version von count.

Antwort

2

Das Problem hierbei ist, dass ein anderer Thread Outer.count direkt lesen konnte, wenn es == 0, weil Sie Outer.count ohne vorher erhalten hat eine Sperre zugreifen können (in der Regel wie in Ihrem Code geschrieben, kann count 0 seine nur vor dem ersten rufen zu Inner.Increment, von da an nur noch einen Wert zwischen 1 und 1001 haben kann)

Lockless kann auf diese Art und Weise erfolgen:

class Inner 
{ 
    public static string Increment(ref int count) 
    { 
     while (true) 
     { 
      int original = count; 
      int next = original; 

      if (next > 1000) 
      { 
       next = 0; 
      } 

      next++; 

      if (Interlocked.CompareExchange(ref count, next, original) == original) 
      { 
       return next.ToString(); 
      } 
     } 
    } 
} 

ich Berechnung einen next Wertes und deren Verwendung (durch Interlocked.CompareExchange) nur ich f count hat sich in der Zwischenzeit nicht geändert.

+0

Das war, was ich dachte, aber würde es den neuesten Wert erhalten, wenn die Lock-Anweisung eingegeben wird (weil es eine Referenz ist) oder wird es mit dem veralteten Wert bleiben? – flukus

+0

@flukus Schau dir meinen modifizierten Code an. – xanatos

+0

Wird das Problem lösen, dass der veraltete Wert von extern weitergegeben wird? – flukus

Verwandte Themen