2010-12-09 13 views
1

I Thread-Sicherheit für besseres Verständnis Testen wurde, und das ist, was ich tat:Objektsperre funktioniert nicht für Threadsicherheit

Ich habe einen Typ ThreadSample genannt, die zwei Methoden haben und dies, wo Verriegelung geschieht:

internal class ThreadTime 
    { 

     public void doSomething(string message) 
     { 
      lock (this) 
      { 
       DialogResult t = MessageBox.Show(message); 
       Thread.Sleep(2000); 
      } 
     } 

     public void anotherLife(string message) 
     { 
      MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message); 
     } 
    } 

Grundsätzlich ist die Idee, wenn doSomething() genannt wird, sollte es die ganze Objekte und andere Threads sperren können sogar anotherLife Methode aufrufen, da sie darauf warten, dass andere Threads die Verriegelung zu lösen.

Das ist die Logik Entriegelungselement zu simulieren:

Wenn Form initialisiert wird, wird eine neue Thread und ThreadSample erstellt:

public partial class Form1 : Form 
{ 
    private ThreadTime time; 
    private Thread thread; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     thread = new Thread(new ThreadStart(workerThread)); 
     time = new ThreadTime(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     thread.Start(); 
     //Thread.Sleep(1000); 
     time.anotherLife("Current thread is = " + "UI Thread"); 
    } 

    private void workerThread() 
    { 
     //time.doSomething("Current thread is = " + Thread.CurrentThread.ManagedThreadId); 
     time.doSomething("Worker Thread"); 
    } 
} 

Wie Sie im Code rechts unten sehen können. Wenn der Benutzer dann auf button1 klickt, wird der Thread gestartet und der UIThread erreicht und ruft anotherLife auf, was zunächst nicht Thread-sicher ist.

Anyways, der Ausgang ist:

  • Es gibt zwei MessageBox zugleich gezeigt.

Was ich erwartet hatte, wenn die neuen Thread doSomething() ruft es die Sperre des Objekts und UIThread wartet auf die Sperre in der Lage sein werden, freigegeben wird anotherLife Methode aufzurufen.

Kann jemand erklären warum?

Danke.

+3

Warum haben Sie das Java-Tag, wenn dies eindeutig C# ist? Und warum verwenden Sie Java-Namenskonventionen in C#? –

+0

So wie ich Ihre Frage gelesen habe, klingt es so, als hätten Sie eine falsche Vorstellung davon, wie Schlösser funktionieren. Eine Sperre für ein Objekt ist nur ein Token für die Synchronisierung. Dem Sperrobjekt selbst passiert nichts. –

+0

Vielleicht bezieht sich der Java-Tag eher auf die Konventionen als auf die Sprache? –

Antwort

5

Was ich erwartet hatte, wenn die neuen Thread ruft doSomething(), es wird die Sperre des Objekts und UIThread wartet auf die Sperre können freigegeben werden anotherLife Methode aufzurufen.

UIThread nicht auf eine Sperre warten, bevor anotherLife ermöglicht freigegeben werden fortgesetzt werden, da anotherLife nicht eine Sperre durchgeführt wird. Beide Threads müssen in eine lock-Anweisung (die auf dasselbe Objekt sperrt) laufen, um das gesuchte Verhalten zu erhalten. Versuchen Sie es zu etwas zu modifizieren, wie:

public void anotherLife(string message) 
{ 
    lock (this) 
    { 
     MessageBox.Show("This is coming from anotherLife method and and current threadNumber is " + message); 
    } 
} 
1

Nun, lock(this) oder lock(someThing) ein bisschen eine irreführende Metapher sein kann.

Es wird nichts unternommen 'to' this, aber das Argument zu lock wird als Token verwendet. Alle Threads, die auf eine bestimmte Ressource zugreifen, müssen dasselbe Token (Objekt) verwenden, um Zugriff anzufordern, andernfalls ist Ihr Code defekt.

Deshalb ist häufig ein Helfer Objekt verwendet wird:

private List<string> myList = ...; 
private object myLock = new object(); 

lock(myLock) 
{ 
    myList.Add("foo"); 
} 

Dieses Schema funktioniert nur, wenn alle Threads auf myLock sperren, bevor myList ändern.
Es gilt als "Best Practice", da nicht garantiert werden kann, dass eine Liste <> sicher gesperrt werden kann.

1

Nur Thread beobachtet das Schloss

Sie müssen sich auf Ihren Code

private void button1_Click(object sender, EventArgs e) 
    { 
     thread.Start(); 
     //Thread.Sleep(1000); 
     time.anotherLife("Current thread is = " + "UI Thread"); 
    } 

zu

private void button1_Click(object sender, EventArgs e) 
    { 
     thread.Start(); 
     //Thread.Sleep(1000); 
lock(time) 
{ 
     time.anotherLife("Current thread is = " + "UI Thread"); 
} 
    } 

Basierend ändern, es scheint, dass Sie denken, auf ein Objekt eine Sperre setzen bedeutet, dass Auf das Objekt kann von nichts anderem zugegriffen werden. Das ist nicht der Fall. Ein Schloss an einem Objekt bedeutet nur ein anderes Schloss darf nicht auf das Objekt gelegt werden, bis das erste Schloss freigegeben wird.

Sie greifen auf das Objekt an zwei Stellen in Ihrem Code zu, einer im Thread und der andere im Button event. Du brauchst ein Schloss an beiden Orten.

+0

Das ist eine nette Erklärung. Vor allem der letzte zweite Absatz. +1 danke. – Tarik

Verwandte Themen