Frage

Ich wollte sehen, was passiert, wenn Sie die Referenz eines ausschließlich durch Monitor.Enter () gesperrt Objekt ändern. Wie erwartet wurde ein SynchronizationLockException geworfen. Aber ich war überrascht, mehr Threads zu sehen, immer vorbei an dem Monitor, bevor die Ausnahme ausgelöst wurde.

Hier ist, was unterhalb der Code tut.

  1. erstellen und starten 100 Threads
  2. macht den Thread warten, bis ein Manual gesetzt.
  3. die Manual gesetzt -. Kinda wie die grüne Fahne an einem Indy-Rennen winken
  4. setzt eine exklusive Sperre (Monitor.Enter (x)) auf x
  5. Verweis der Änderung x.

An dieser Stelle ich eine Art von Ausnahme zu erwarten geworfen, aber das geschieht nicht, bis Monitor.Exit (x). Was wirklich seltsam ist, dass 10 bis 20 Fäden über die Sperre bekommen scheinen zu können, bevor die Ausnahme. Wie kommt das? Scheint nicht, wie es sollte. Natürlich die Referenz des ausschließlich gesperrte Objekts zu ändern ist ein No-No. Ich würde es nie in echtem Code tun, aber immer noch war ich überrascht, dass die andere Threads zu sehen, hinter dem Monitor zu bekommen. Ihre Gedanken?

using System;
using System.Threading;

namespace ThreadingPlayground
{
  class Program
  {
    private int _value;
    object x = new object();

    ManualResetEvent _event = new ManualResetEvent(false);

    static void Main()
    {
      Program p = new Program();
      p.StartThreads();
      Console.ReadLine();
    }

    private void StartThreads()
    {

      for(int i = 0;i<100;i++)
      {
        Thread t = new Thread(IncrementValue);
        t.Start();
      }
      _event.Set();
    }

    private void IncrementValue()
    {
      WaitHandle.WaitAll(new WaitHandle[] {_event});

      Monitor.Enter(x);

      // Change the reference of the exclusively locked object. This 
      // allows other threads to enter, should this be possible?
      x = Thread.CurrentThread.ManagedThreadId.ToString();

      Console.WriteLine(++_value);

      // throws a SynchronizationLockException 
      // but not until 10 - 20 more lines are written
      Monitor.Exit(x);
    }
  }
}

War es hilfreich?

Lösung

Was Sie sehen, Verhalten wird erwartet. Es ist nichts Besonderes über die tatsächliche Variable verwendet einen Verweis in Monitor.Enter() passieren. Ändern die Referenz sollte nicht andere Threads verhindert, dass eine exklusive Sperre zu erwerben, da die Variablen einen neuen Wert hat, und das Bezug ist nicht überall verriegelt.

Ihr Problem kommt mit dem Exit, da der Thread ruft Exit in nicht eine exklusive Sperre auf der Referenz haben wird übergeben. Ein anderer Thread auch eine Sperre auf sie haben, aber der Thread Sie in tut bist Ausführung nicht.

Dies ist, wie Sie wissen, ist, warum es ist immer am besten Ihre Schließanlage mit einer Variablen, deren Bezug zu tun, wird sich nie ändern. Wenn die Variable Ihre Ressource könnte, eine neue Referenz verwenden ändern.

Ist das klar genug?

Andere Tipps

‚x‘ ist eine Referenz auf ein Objekt; es ist nicht das Objekt selbst. Wenn Sie das tun

      x = Thread.CurrentThread.ManagedThreadId.ToString();

Sie haben das gesperrte Objekt weggeworfen, die zuvor genannten X und hergestellt x zu einem anderen Objekt bezieht. Nun, wenn Sie tun

      Monitor.Exit(x);

Sie erhalten die Ausnahme, da dieses Objekt in der Tat nicht gesperrt ist - das Objekt, das Sie Müll ist jetzt gesperrt vom Garbage Collector gesammelt wird

.

Der Grund für dieses Verhalten ist, dass man den Wert von x hier ist zu ändern:

x = Thread.CurrentThread.ManagedThreadId.ToString();

Also, wenn Sie bekommen

Monitor.Exit(x)

Sie Lösen der Verriegelung mit einem anderen Objekt. Es ist, als ob Sie ein Vorhängeschloss mit einem Schlüssel setzen, und versuchen, das Schloss mit dem Schlüssel aus einem anderen Schloss zu entfernen.

Darüber hinaus Console.WriteLine ist eine kostspielige Anweisung im Vergleich zu dem anderen, so dass mehrere Threads erhalten den Monitor eingegeben werden, bevor einer von ihnen in der Nähe der Ziellinie wird.

Hier ist ein Beispiel Lauf:

Sie beginnen eine Reihe von Themen.

  • Thread T1 erwirbt das Schloss mit dem Objekt x.
  • T2 versucht Sperre mit dem Objekt x zu erwerben. Dieser Thread ist kein Glück, wie wir es geht warten wissen, für immer.
  • T1 Änderungen x. Es ist jetzt ein neues Objekt. Ich nenne es x'1.
  • T3 versucht, die Sperre zu erwerben. Aber der Variable x verweist das Objekt tatsächlich x'1. Niemand hat sich auf x'1 gesperrt, so dass er geht.
  • T3 Änderungen x. Es ist jetzt ein neues Objekt namens x'3.
  • T1 schreibt an die Konsole.
  • T3 schreibt an die Konsole.
  • T1 versucht, das Schloss mit der variablen x zu lösen, die auf das Objekt verweist ... x'3.
  • Die Monitor Objekt sagt: „Hey, was denkst du, was du tun Sie nicht, dass die Sperre haben Essen Sie dieses Ausnahme kleine Sauger?!“
  • Fin
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top