קצת על Pulse, PulseAll, Wait ב .NET

נניח שיש לנו שני thread - ים.
שניהם עושים lock על אובייקט כלשהו.
thread א' מבצע לוגיקה עד שיש לו אפשרות במידה ומישהו זקוק לזה, לשחרר לזמן מסוים את האובייקט המוחזק ואם לא (אף אחד לא ירצה בכך), להמשיך בפעילות.
thread ב' מחכה זמן מה שישוחרר לו האובייקט שעליו גם הוא עושה lock. בתוך ה lock הוא עושה Monitor.Wait על האובייקט.

thread א' שולח Monitor.Pulse על האובייקט שנקלט על ידי thread ב'. מכאן מתחיל לבצע הקוד של thread ב' וכך גם ה lock על האובייקט בפועל עובר אליו.

אם יש לנו כמה thread ים נוספים שעושים lock/wait על אותו אובייקט ואנחנו נרצה לשחרר את כולם במקביל מהחסימה, נריץ Monitor.PulseAll על האובייקט.

יש לשים לב ש ה Monitor.Wait מופעל על אובייקט שנמצא בתוך lock, אחרת נקבל exception.


namespace threads
{
class Program
{
object commonResource = new object();
public void increment()
{
while (true)
{
lock (commonResource)
{
Console.WriteLine("Ping");
//working hard
Monitor.Pulse(commonResource);
Thread.Sleep(1000);
}
}
}

public void decrement()
{
while (true)
{
lock (commonResource)
{
Monitor.Wait(commonResource);
Console.WriteLine("Pong");
}
}
}
public void start()
{
Thread a = new Thread(new ThreadStart(increment));
a.IsBackground = false;
Thread b = new Thread(new ThreadStart(decrement));
b.IsBackground = false;
a.Start();
b.Start();
}

static void Main(string[] args)
{
Program p = new Program();
p.start();
}
}
}

למעשה מדובר במעטפת על שני סוגי Events - AutoResetEvent, ManualResetEvent.
הראשון - ManualResetEvent כאשר מקבל את הסימן Set בעצם משחרר את כל מי שמחכה לו וכדי להחזיר אותו לקדמותו יש לבצע Reset בצורה ידנית בדומה ל PulseAll.
השני AutoResetEvent גם כן מופעל באמצעות Set אבל משחרר רק את ה Thread הראשון שעושה לו Wait. בדומה ל Pulse.

3 Comments

  1. לא מבין כלום

    ReplyDelete
  2. מסכים עם אנונימי א

    ReplyDelete
  3. אפשר להגיד שמדובר בקיצור דרך. אחרת היינו צריכים להגדיר משתנה מסוג AutoResetEvent ואז לעשות לו set.
    פה זה מעטפת שעושה את זה בשבילנו... כמו שlock היא מעטפת בפני עצמה.

    ReplyDelete
Previous Post Next Post