המדריך לתכנות מקבילי בשפת C Sharp – פרק ג' – IsAlive & Join

בפרקים הקודמים של המדריך ראינו כיצד ביכולתנו לבצע Multithreading. בפרק זה נלמד על Join & IsAlive וניווכח כיצד נוכל להיעזר בהם.

אם נחזור לרגע לתוכנית אשר כתבנו בפרק הראשון של המדריך,
נוכל להבחין שהמתודה הראשונה לא ממתינה שהשנייה והשלישית יסיימו את פעולתן,
כלומר שהן רצות בצורה מקבילית.
חשוב להבין כי Thread 1,2,3 הם למעשה יורשים של ה-Thread המרכזי,
וזאת משום שהן נוצרו על ידיו.
כלומר שה-Thread המרכזי לא יסיים את פעולתו – עד שה-Threads יסיימו את פעולתם.
שימו לב לדוגמא זו אשר נלקחה מהפרק הראשון:

using System.Threading;
 
namespace Threading1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(">>>Main Thread Started\n");
            //Creating Threads
            Thread thread1 = new(MyMethod1)
            {
                Name = "Thread1"
            };
            Thread thread2 = new(MyMethod2)
            {
                Name = "Thread2"
            };
            Thread thread3 = new(MyMethod3)
            {
                Name = "Thread3"
            };
            //Executing the methods
            thread1.Start();
            thread2.Start();
            thread3.Start();
            Console.WriteLine(">>>Main Thread Ended\n");
        }
        static void MyMethod1()
        {
            Console.WriteLine($"\n>>>MyMethod1 Started using {Thread.CurrentThread.Name}\n");
            Thread.Sleep(3000);
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("MyMethod1 :" + i);
            }
            Console.WriteLine($"\n>>>MyMethod1 Endded using {Thread.CurrentThread.Name}\n");
        }
 
        static void MyMethod2()
        {
            Console.WriteLine($">>>MyMethod2 Started using {Thread.CurrentThread.Name}\n");
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("MyMethod2 :" + (i*2));
            }
            Console.WriteLine($"\n>>>MyMethod2 Endded using {Thread.CurrentThread.Name}\n");
        }
        static void MyMethod3()
        {
            Console.WriteLine($">>>MyMethod3 Started using {Thread.CurrentThread.Name}\n");
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("MyMethod3 :" + (i*i));
            }
            Console.WriteLine($"\n>>>MyMethod3 Endded using {Thread.CurrentThread.Name}\n");
        }
    }
}

הרצת קוד זה למעשה מראה לנו שאכן כך הדבר.
אך מה אם היינו רוצים דווקא לחסום Thread מסוים מלרוץ עד אשר ה-Thread היורש יסיים את פעולתו?

המתודה ()Join

במתודה Join נוכל להשתמש על מנת להשהות את ה-Thread הנוכחי עד אשר יורשיו יסיימו את פעולתם.
ישנם 3 העמסות למתודה Join במחלקת Thread:

Multithreading - Join Method
Multithreading – Join Method
  • ()Join – משהה את ה-Thread אשר קרא למתודה – עד אשר ה-Threads שיורשים ממנו יסיימו את פעולתם.
  • Join(int millisecondsTimeout) – משהה את ה-Thread אשר קרא למתודה – עד אשר ה-Threads שיורשים ממנו יסיימו את פעולתם, או שמגיע זמן ה-Timeout שהעברנו בפרמטר,
    אם ה-Thread ימשיך לרוץ לאחר תום הזמן שהוגדר – תיזרק חריגת ArgumentOutOfRangeException,
    נוכל לתת כערך את System.Threading.Timeout.Infinite על מנת שהזמן המוגדר יהיה אינסופי.
    אם ה-Thread לא יתחיל לרוץ בכלל – תיזרק חריגת ThreadStateException.
  • Join(TimeSpan timeout) – זהה לקודם, ההבדל הוא ביחידות הזמן שנעביר כפרמטר

 

שימו לב ל-Code Snippet הבא:

using System.Threading;

namespace ThreadingDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main Thread Started");
            //Main Thread creating three child threads
            Thread thread1 = new(MyMethod1);
            Thread thread2 = new(MyMethod2);
            Thread thread3 = new(MyMethod3);

            thread1.Start();
            thread2.Start();
            thread3.Start();

            thread1.Join();
            thread2.Join();
            thread3.Join();

            Console.WriteLine("Main Thread Ended");
        }
        static void MyMethod1()
        {
            Console.WriteLine("MyMethod1 - Thread1 Started");
            Thread.Sleep(5000);
            Console.WriteLine("MyMethod1 - Thread1 Ended");
        }
        static void MyMethod2()
        {
            Console.WriteLine("MyMethod2 - Thread2 Started");
            Thread.Sleep(2000);
            Console.WriteLine("MyMethod2 - Thread2 Ended");
        }
        static void MyMethod3()
        {
            Console.WriteLine("MyMethod3 - Thread3 Started");
            Thread.Sleep(1000);
            Console.WriteLine("MyMethod3 - Thread3 Ended");
        }
    }
}

אם תריצו קטע קוד זה, תוכלו להבחין כי ה-Thread המרכזי לא סיים את פעולתו עד אשר יורשיו סיימו את פעולתם, בדיוק כפי שהוסבר:

Multithreading - Join Method - Output
Multithreading – Join Method – Output

כלומר שאם לא היינו מעוניינים לחכות ל-Thread1 (שהפעולה שלו אורכת כ-5 שניות), פשוט לא היינו עושים לו Join.
אם תסירו את שורה 19 ותריצו שוב, תתקבל תוצאה דומה לזו:

Multithreading - Join Method - Output
Multithreading – Join Method – Output

המאפיין IsAlive

במאפיין זה נוכל להשתמש על מנת לקבל את הסטטוס של ה-Thread.
אם מחזיר לנו True – ה-Thread אכן רץ,
אם מחזיר לנו False -סימן שה-Thread סיים את פעולתו.
שימו לב לדוגמא הבאה שבה ניישם קונספט זה על ידי שימוש במתודה משותפת ל-Threads:

using System.Threading;

namespace ThreadingDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main Thread Started");
            //Main Thread creating three child threads
            Thread thread1 = new(MyMethod1)
            { 
                Name = nameof(MyMethod1) 
            };
            Thread thread2 = new(MyMethod2)
            {
                Name = nameof(MyMethod2)
            };
            Thread thread3 = new(MyMethod3)
            {
                Name = nameof(MyMethod3)
            };

            thread1.Start();
            thread2.Start();
            thread3.Start();

            Console.WriteLine("\n************* IsAlive Check: ******************");
            IsAliveCheck(thread1);
            IsAliveCheck(thread2);
            IsAliveCheck(thread3);
            Console.WriteLine("***********************************************\n");

            thread2.Join();
            thread3.Join();

            Console.WriteLine("\n************* IsAlive Check: ******************");
            IsAliveCheck(thread1);
            IsAliveCheck(thread2);
            IsAliveCheck(thread3);
            Console.WriteLine("***********************************************\n");

            Console.WriteLine("Main Thread Ended");

            Console.WriteLine("\n************* IsAlive Check: ******************");
            IsAliveCheck(thread1);
            IsAliveCheck(thread2);
            IsAliveCheck(thread3);
            Console.WriteLine("***********************************************\n");
        }
        static void IsAliveCheck(Thread thread)
        {
            if (thread.IsAlive)
            {
                Console.WriteLine($"{thread.Name} is working");
            }
            else
            {
                Console.WriteLine($"{thread.Name} is not working");
            }
        }
        static void MyMethod1()
        {
            Console.WriteLine("MyMethod1 - Thread1 Started");
            Thread.Sleep(5000);
            Console.WriteLine("MyMethod1 - Thread1 Ended");
        }
        static void MyMethod2()
        {
            Console.WriteLine("MyMethod2 - Thread2 Started");
            Thread.Sleep(2000);
            Console.WriteLine("MyMethod2 - Thread2 Ended");
        }
        static void MyMethod3()
        {
            Console.WriteLine("MyMethod3 - Thread3 Started");
            Thread.Sleep(1000);
            Console.WriteLine("MyMethod3 - Thread3 Ended");
        }
    }
}

בדקנו את הסטטוס של ה-Threads שיצרנו בכל אחד משלבי התכנית,
ולכן קיבלנו את התוצאה הבאה:

Multithreading - IsAlive Property
Multithreading – IsAlive Property

תוכלו להבחין במספר דברים:

  • מהסיבה שיש בתוכנית זו מתודות שרצות במקביל ללא טיפול סינכרוני – ההדפסה של Thread3 נכנסה לתוך ההדפסה של – IsAliveCheck.
  • בזמן הבדיקה האחרונה שביצענו, Thread1 טרם סיים את פעולתו.
  • Thread1 סיים את פעולתו לאחר שה-Thread המרכזי סיים את פעולתו – תקין לדעתכם?

 

כעת, לאחר שהבנו את אופן הפעולה של Join & IsAlive,
בפרק הבא של מדריך זה נלמד על סינכרוניות בתכנות מקבילי על מנת שנוכל לקבל תשובות לשאלות שנשארו פתוחות כתוצאה ממאמר זה.
לקריאה מורחבת על Thread ו-Threading באתר של מייקרוסופט יש ללחוץ כאן.

רוצים לשתף את המדריך?

אהבתכם את המדריך? פתר לכם תקלה?

גולשים יקרים, רוב התכנים המוצגים באתר נכתבים בהתנדבות מלאה מתוך כוונה להנגיש מידע עבורכם. אם נתקלתם במדריך חינמי שפתר לכם תקלה או לימד אתכם משהו חדש שלא ידעתם, וברצונכם לתגמל את כותב המדריך או סתם להזמין אותו לכוס קפה, הינכם יותר ממוזמנים לתרום.

כתיבת תגובה

הזמינו אותי לכוס קפה
buy me coffee

אהבתכם את המדריך? פתר לכם תקלה? הזמינו את כותב המדריך לכוס קפה

גולשים יקרים, רוב התכנים המוצגים באתר נכתבים בהתנדבות מלאה מתוך כוונה להנגיש מידע עבורכם. אם נתקלתם במדריך חינמי שפתר לכם תקלה או לימד אתכם משהו חדש שלא ידעתם, וברצונכם לתגמל את כותב המדריך או סתם להזמין אותו לכוס קפה, הינכם יותר ממוזמנים לתרום.