2017-11-18 6 views
2

Ich versuche vollständig zu verstehen, wie das Erstellen separater Threads, die die gleiche Methode einer Klasseninstanz aufrufen, lokale Variablen in der Methode beeinflussen kann.Multi Threading freigegebene lokale Variablen

Zum Beispiel habe ich eine Klasse mit einer einzigen Methode (Teilen)

public class Maths 
{ 
    public int Num1; 
    public int Num2; 

    public void Divide() 
    { 
     for (long i = 0; i < 100000; i++) 
     { 
      Num1 = 2; 
      Num2 = 2; 
      int result = Num1/Num2; 
      Num1 = 0; 
      Num2 = 0; 
     } 
    } 
} 

zwei Threads instanziiert und die Kluft Methode wie folgt aufgerufen:

static void Main(string[] args) 
    { 
     Maths m = new Maths(); 

     Task t1 = new Task(() => m.Divide()); 
     Task t2 = new Task(() => m.Divide()); 

     List<Task> tl = new List<Task> { t1, t2 }; 
     Parallel.ForEach(tl, task => task.Start()); 

     Console.ReadLine(); 
    } 

} 

Manchmal dieser Code ok läuft. Aber zu anderen Zeiten wird ein divebyzero-Fehler in der Zeile ausgegeben:

int result = Num1/Num2;

Meine Annahme ist, dass einer der Threads die Num1 und Num2 auf Null zurücksetzt, kurz bevor der andere Thread die Num1/Num2 aufruft. Daher verursacht eine Division durch Null Ausnahme.

Das würde Sinn machen und ich sollte eine Sperre verwenden, aber ich verstehe nicht, wie diese lokalen Variablen Num1 und Num2 zwischen den Threads geteilt werden, da mein Verständnis war, dass lokale Variablen nicht zwischen Threads geteilt werden?

+0

Danke, das macht jetzt Sinn. – selams

Antwort

5

Sie haben Recht, dass lokale Variablen nicht zwischen Threads geteilt werden (normalerweise wird jede Zeitmethode aufgerufen, neue Mengen ihrer lokalen Variablen werden auf dem Stack des ausführenden Threads zugewiesen, sodass lokale Variablen jedes Methodenaufrufs vollständig voneinander getrennt sind) Änderung von einem von ihnen hat keinen Einfluss auf die anderen).

Aber unglücklicherweise Num1 und Num2 sind keine lokalen Variablen, aber fields. Felder derselben Instanz einer Klasse werden zwischen Threads geteilt.

Sie müßten sie so declate ihnen lokale Variablen zu machen:

public class Maths 
{ 
    public void Divide() 
    { 
     int Num1; 
     int Num2; 

     for (long i = 0; i < 100000; i++) 
     { 
      Num1 = 2; 
      Num2 = 2; 
      int result = Num1/Num2; 
      Num1 = 0; 
      Num2 = 0; 
     } 
    } 
} 

Alternativ coud Sie separate Instanz Maths Klasse für jeden Thread erstellen, so dass jeder Thread verwenden würde Felder Num1 und Num2 verschiedenen Instanzen von Maths Klasse:

static void Main(string[] args) 
{ 
    Maths m1 = new Maths(); 
    Maths m2 = new Maths(); 

    Task t1 = new Task(() => m1.Divide()); 
    Task t2 = new Task(() => m2.Divide()); 

    List<Task> tl = new List<Task> { t1, t2 }; 
    Parallel.ForEach(tl, task => task.Start()); 

    Console.ReadLine(); 
} 
+0

Perfekte Antwort und gut erklärt! –

3

Da Sie das gleiche Objekt, werden alle Updates Aktionen auf die andere auswirken in einer Aufgabe verwenden.

+2

... aber nur, da Num1 und Num2 Felder sind und nicht lokale vars, wie Nuf erklärt –

+0

Ja, Nuf Antwort erklären es besser. – Felipe