המדריך לתכנות מקבילי בשפת C Sharp – פרק א' – Multithreading

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

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

Multitasking vs Multithreading

ראשית, עלינו להבין את ההבדל שבין  Multitasking ל-Multithreading.
כאשר אנו מדברים על ריבוי תהליכים בתוכנית שלנו אין אנו מתכוונים ל-Multitasking.
הווינדוס שלנו לדוגמא היא מערכת אשר תומכת בריבוי תהליכים,
כלומר שנוכל להפעיל מספר תכניות במקביל (דפדפן, כתבן וכו').
אם נלחץ Ctrl+Alt+Delete ונלחץ על מנהל המשימות (Task Manager) נוכל לראות אילו תהליכים פועלים כרגע:

C Sharp Multithreading
C Sharp Multithreading

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

מחלקת Thread

כל המחלקות אשר קשורות ל-Threading ב-C# שייכות ל-System.Threading namespace.
למחלקת Thread יש מאפיין סטטי מסוג-Thread בשם CurrentThread, אשר מחזיר את המופע של ה-Thread שרץ ברגע זה.
במאפיין – Name נוכל להשתמש על מנת לתת שם למופע ה-Thread:

using System.Threading;

namespace Threading1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Thread mainThread = Thread.CurrentThread;
            mainThread.Name = "Main Thread";
            Console.WriteLine("Current Executing Thread Name :" + Thread.CurrentThread.Name);
        }
    }
}

הרצת Code Snippet זה למעשה מוכיחה לנו כי כל תוכנית היא בעלת Thread אחד באופן דיפולטיבי.

החסרונות בעבודה עם Thread יחיד

בתוכניות אשר עובדות עם Thread בודד, כל הקוד של התוכנית יורץ על ידי Thread אחד בלבד.
לדוגמא, נניח ויש לנו תכנית אשר לה 3 פונקציות, ואנחנו הולכים לקרוא לפונקציות הללו מה-Thread הראשי,
הפונקציות ירוצו אחת אחרי השניה (באופן דיפולטיבי).
שימו לב לדוגמא הבאה:

using System.Threading;

namespace Threading1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MyMethod1();
            MyMethod2();
            MyMethod3();
        }
        static void MyMethod1()
        {
            for (int i = 1; i >= 5; i++)
            {
                Console.WriteLine("MyMethod1 :" + i);
            }
            Console.WriteLine();
        }

        static void MyMethod2()
        {
            for (int i = 1; i >= 5; i++)
            {
                Console.WriteLine("MyMethod2 :" + (i*2));
            }
            Console.WriteLine();
        }
        static void MyMethod3()
        {
            for (int i = 1; i >= 5; i++)
            {
                Console.WriteLine("MyMethod3 :" + (i*i));
            }
            Console.WriteLine();
        }
    }
}
C Sharp Single Thread
C Sharp Single Thread

אז מה הבעיה בקוד הזה?

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

Thread.Sleep(10000);

כיצד ניתן לפתור את הבעיה?

לשם פתרון בעיה זו, בשפת C Sharp קיים קונספט אשר נקרא Multithreading.
בתחילת המאמר הבנו מהו תהליך מערכת של הווינדוס,
ובכן, כל תהליך כזה יכול להריץ מספר תתי תהליכים באופן מקבילי.
מיד נבאר את הנושא

Multithreading

אם נרצה שכל פונקציה תרוץ במסגרת Thread משלה באופן מקבילי נוכל לכתוב את התוכנית שלנו כך:

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");
        }
    }
}

שימו לב שבפונקציה הראשונה הכנסנו שורת קוד שתגרום לה להימשך כ-3 שניות (שורה 32).
כעת אם נריץ את התוכנית יקרו הדברים הבאים:

  • יופעלו שלושת ה-threads שיצרנו.
  • הפונקציה הראשונה תיכנס לפעולה (יארך כ-3 שניות).
  • הפונקציות השנייה והשלישית ירוצו בינתיים כרגיל ויסיימו את פעולתן
  • הפונקציה הראשונה תסיים את פעולתה
C Sharp Multithreading
C Sharp Multithreading

כעת, לאחר שהבנו את רעיון ה-MultiThreading באופן כללי,
נוכל להמשיך אל הפרק הבא של שבו נסביר על הבנאי של מחלקת Thread.
לקריאה מורחבת על Thread ו-Threading באתר של מייקרוסופט יש ללחוץ כאן.

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

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

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

כתיבת תגובה

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

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

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