Im vorhergehenden Artikel dieser Serie habe ich Ihnen vorgestellt, wie sie eine Signalisierung zwischen unterschiedlichen Threads mittels der Event Wait Handle Klassen implementieren können. Heute möchte ich Ihnen eine weitere Form der Signalisierung aufzeigen. Diese wird von der Monitor Klasse durch die Funktionen Wait und Pulse bereitgestellt.
Wait and Pulse Pattern
Die Monitor Klasse stellt Ihnen die grundlegenden Signalisierungsfunktionen bereit. Um diese anzuwenden, müssen Sie aber selbst die entsprechende Signalisierungslogik schreiben und mittels lock-Befehlen schützen. Mittels der Wait und Pulse Befehle der Monitor Klasse können Sie diese Signalisierungslogik danach erweitern und dadurch Polling Loops vermeiden. Damit erhalten Sie eine sehr leistungsfähige und schnelle Signalisierungsfunktionalität.
Für diese Implementierung möchte ich Ihnen nachfolgend ein allgemeines Pattern zeigen.
1. Definieren Sie ein Synchronisierungsobjekt:
readonly object _locker = new object();
2. Definieren Sie die Variablen die Sie für ihre Signalisierungslogik benötigen. In diesem Beispiel wird eine boolesche Variable angelegt.
bool _continue;
3. Erzeugen Sie die Block-Anweisungen an den Stellen an denen Sie auf die entsprechende Signalisierung warten wollen.
lock (_locker)
{
while ( <blocking-condition> )
{
Monitor.Wait (_locker);
}
}
4. Erzeugen Sie die Signalisierungsfunktionalität an den Stellen an denen Sie die entsprechende Signalisierung auslösen wollen.
lock (_locker)
{
<blocking-condition> aktualisieren
Monitor.Pulse(_locker);
}
Beispiel
Im nachfolgenden Beispiel sehen Sie eine Konsolenanwendung bei der das beschriebene Pattern eingesetzt wurde, um die Signalisierung zwischen zwei Threads zu implementieren.
Es werden das Lock-Objekt und ein boolescher Wert für die Signalisierungslogik angelegt. Anschliessend werden zwei Threads gestartet. Der erste Thread enthält die Funktionalität zum Warten auf das Signalisierungsereignis. Der zweite Thread führt diese Signalisierung nach einer kurzen Pause von drei Sekunden aus.
static readonly object _locker = new object(); static bool _continue; static void Main() { Parallel.Invoke( ThreadWait, ThreadPulse); Console.ReadKey(); } static void ThreadWait() { lock (_locker) { while (_continue == false) { Monitor.Wait(_locker); } } Console.WriteLine("Signal received"); } static void ThreadPulse() { Thread.Sleep(3000); lock (_locker) { _continue = true; Monitor.Pulse(_locker); } Console.WriteLine("Signal send"); }
Fazit
Mittels der Montitor.Block und Monitor.Pulse Funktionen lässt sich eine leistungsfähige Signalisierungsfunktionalität zwischen Threads erzeugen. Das vorgestellte Pattern liefert Ihnen dabei ein einfaches Grundgerüst welches Sie für die Implementierung Ihrer Wait und Pulse Abläufe verwenden können.