1. نظرة عامة على الموضوع
المواضيع هي وحدة التنفيذ الأساسية لتنفيذ البرنامج. عندما يقوم نظام التشغيل (باستثناء أنظمة التشغيل ذات الخيط الواحد، مثل نظام DOS المبكر من Microsoft) بتنفيذ برنامج ما، سيتم إنشاء عملية في النظام، وفي هذه العملية، يجب إنشاء خيط واحد على الأقل (يسمى هذا الخيط الرئيسي Thread) كنقطة دخول لتشغيل هذا البرنامج. ولذلك، فإن أي برنامج يعمل في نظام التشغيل يحتوي على مؤشر ترابط رئيسي واحد على الأقل.
تعد العمليات والخيوط نموذجين تشغيليين أساسيين في أنظمة التشغيل الحديثة. يمكن أن يكون هناك عمليات متعددة في نظام التشغيل، بما في ذلك عمليات النظام (العمليات التي تم إنشاؤها داخليًا بواسطة نظام التشغيل) وعمليات المستخدم (العمليات التي تم إنشاؤها بواسطة برامج المستخدم) ؛ لا توجد ذاكرة مشتركة بين العمليات، مما يعني أن العمليات في النظام تعمل في مساحات الذاكرة المستقلة الخاصة بها. يمكن للخيوط الموجودة في العملية مشاركة مساحة الذاكرة المخصصة من قبل النظام لهذه العملية.
لا يمكن للخيوط مشاركة ذاكرة العملية فحسب، بل تحتوي أيضًا على مساحة ذاكرة خاصة بها وتسمى أيضًا مساحة الذاكرة هذه التي يتم تخصيصها بواسطة النظام عند إنشاء مؤشر الترابط البيانات المستخدمة داخل الخيط، مثل متغيرات الخيط المحددة في وظيفة التنفيذ.
ملاحظة: سيقوم أي مؤشر ترابط بتنفيذ وظيفة عند إنشائه، وتسمى هذه الوظيفة بوظيفة تنفيذ الخيط. يمكن أيضًا اعتبار هذه الوظيفة بمثابة نقطة دخول للخيط (على غرار الوظيفة الرئيسية في البرنامج). بغض النظر عن اللغة أو التقنية المستخدمة لإنشاء سلسلة رسائل، يجب تنفيذ هذه الوظيفة (قد يكون التعبير عن هذه الوظيفة مختلفًا، ولكن ستكون هناك دائمًا مثل هذه الوظيفة). على سبيل المثال، المعلمة الثالثة لوظيفة API CreateThread المستخدمة لإنشاء مؤشر ترابط في Windows هي مؤشر وظيفة التنفيذ هذه.
بعد أن يقسم نظام التشغيل العملية إلى سلاسل عمليات متعددة، يمكن تنفيذ هذه الخيوط بشكل متزامن تحت إدارة نظام التشغيل، وبالتالي تحسين كفاءة تشغيل البرنامج بشكل كبير. على الرغم من أن تنفيذ سلاسل العمليات يبدو وكأنه عدة سلاسل يتم تنفيذها في نفس الوقت من منظور ماكرو، إلا أن هذا في الواقع مجرد غطاء لنظام التشغيل. نظرًا لأن وحدة المعالجة المركزية يمكنها تنفيذ تعليمات واحدة فقط في كل مرة، فمن المستحيل تنفيذ مهمتين في نفس الوقت على جهاز كمبيوتر مزود بوحدة معالجة مركزية واحدة. من أجل تحسين كفاءة تشغيل البرنامج، سيقوم نظام التشغيل بإزالة الخيط عندما يكون خاملاً ويسمح للسلاسل الأخرى بتنفيذه. وتسمى هذه الطريقة بجدولة الخيط. السبب وراء رؤية عدة سلاسل يتم تنفيذها في نفس الوقت على السطح هو أن وقت التبديل بين سلاسل مختلفة قصير جدًا، وفي الظروف العادية يكون التبديل متكررًا جدًا. لنفترض أن لدينا المواضيع A و B. في وقت التشغيل، من الممكن أنه بعد تنفيذ A لمدة 1 مللي ثانية، وبعد التبديل إلى B، يتم تنفيذ B لمدة 1 مللي ثانية أخرى، ثم يتحول إلى A، ويتم تنفيذ A لمدة 1 مللي ثانية أخرى. نظرًا لأنه يصعب على الأشخاص العاديين إدراك 1 مللي ثانية، يبدو ظاهريًا أنه يتم تنفيذ A وB في نفس الوقت، ولكن في الواقع يتم تنفيذ A وB بالتناوب.
2. الفوائد التي تجلبها لنا الخيوط
يمكن أن يؤدي الاستخدام السليم للخيوط إلى تقليل تكاليف التطوير والصيانة وحتى تحسين أداء التطبيقات المعقدة. على سبيل المثال، في تطبيقات واجهة المستخدم الرسومية، يمكن معالجة الأحداث بشكل أفضل من خلال الطبيعة غير المتزامنة للخيوط؛ في برامج خادم التطبيقات، يمكن إنشاء خيوط متعددة للتعامل مع طلبات العميل. يمكن أن تعمل الخيوط أيضًا على تبسيط تنفيذ الأجهزة الافتراضية، على سبيل المثال، عادةً ما يتم تشغيل أداة تجميع البيانات المهملة لجهاز Java Virtual Machine (JVM) في مؤشر ترابط واحد أو أكثر. ولذلك فإن استخدام الخيوط سيؤدي إلى تحسين تطبيقاتنا في الجوانب الخمسة التالية:
1. الاستفادة الكاملة من موارد وحدة المعالجة المركزية
تحتوي معظم أجهزة الكمبيوتر في العالم الآن على وحدة معالجة مركزية واحدة فقط. لذلك، من المهم بشكل خاص الاستفادة الكاملة من موارد وحدة المعالجة المركزية. عند تنفيذ برنامج أحادي الترابط، قد تكون وحدة المعالجة المركزية في وضع الخمول أثناء حظر البرنامج. سيؤدي هذا إلى إهدار الكثير من موارد الحوسبة. يمكن أن يؤدي استخدام مؤشرات الترابط المتعددة في أحد البرامج إلى تشغيل مؤشرات ترابط أخرى عندما يكون مؤشر الترابط في وضع السكون أو الحظر وتكون وحدة المعالجة المركزية في وضع الخمول. بهذه الطريقة، من الصعب أن تظل وحدة المعالجة المركزية في وضع الخمول. ولذلك، يتم استخدام موارد وحدة المعالجة المركزية بالكامل.
2. تبسيط نموذج البرمجة
إذا أكمل البرنامج مهمة واحدة فقط، فما عليك سوى كتابة برنامج ذو خيط واحد وكتابة الكود وفقًا لخطوات تنفيذ المهمة. ولكن لإكمال مهام متعددة، إذا كنت لا تزال تستخدم مؤشر ترابط واحد، فيجب عليك أن تحدد في البرنامج ما إذا كان يجب تنفيذ كل مهمة ومتى. على سبيل المثال، يعرض الساعات والدقائق والثواني للساعة. إذا كنت تستخدم خيطًا واحدًا، فيجب عليك الحكم على وقت الدوران وزاوية هذه المؤشرات الثلاثة واحدًا تلو الآخر في الحلقة. إذا تم استخدام ثلاثة مؤشرات ترابط للتعامل مع عرض هذه المؤشرات الثلاثة، فهذا يعني إجراء مهمة منفصلة لكل مؤشر ترابط. وهذا يساعد المطورين على فهم البرنامج والحفاظ عليه.
3. تبسيط معالجة الأحداث غير المتزامنة
عندما يتلقى تطبيق خادم اتصالات عميل مختلفة، فإن أبسط طريقة للتعامل معها هي إنشاء سلسلة رسائل لكل اتصال عميل. يظل مؤشر ترابط الاستماع مسؤولاً عن الاستماع للطلبات الواردة من العميل. إذا تمت معالجة هذا النوع من التطبيقات بواسطة مؤشر ترابط واحد، عندما يتلقى مؤشر ترابط الاستماع طلب العميل، فإنه يبدأ في قراءة البيانات المرسلة من قبل العميل، بعد قراءة البيانات، يتم حظر طريقة القراءة، أي هذا الموضوع لن يتمكن بعد الآن من الاستماع إلى طلبات العميل. إذا كنت تريد معالجة طلبات عملاء متعددة في مؤشر ترابط واحد، فيجب عليك استخدام اتصالات مأخذ التوصيل غير المحظورة والإدخال/الإخراج غير المتزامن. ومع ذلك، يعد استخدام الإدخال/الإخراج غير المتزامن أكثر صعوبة في التحكم وأكثر عرضة للخطأ من استخدام الإدخال/الإخراج المتزامن. ولذلك، يمكن التعامل مع الأحداث غير المتزامنة مثل الطلبات المتعددة بسهولة أكبر باستخدام تعدد مؤشرات الترابط والإدخال/الإخراج المتزامن.
4. جعل واجهة المستخدم الرسومية أكثر كفاءة
عند استخدام مؤشر ترابط واحد لمعالجة أحداث واجهة المستخدم الرسومية، يجب استخدام حلقة للبحث عن أحداث واجهة المستخدم الرسومية التي قد تحدث في أي وقت داخل الحلقة، بالإضافة إلى البحث عن أحداث واجهة المستخدم الرسومية، يجب تنفيذ رموز البرامج الأخرى. إذا كانت التعليمات البرمجية طويلة جدًا، فسيتم "تجميد" أحداث واجهة المستخدم الرسومية حتى يتم تنفيذ التعليمات البرمجية.
في أطر عمل واجهة المستخدم الرسومية الحديثة (مثل SWING وAWT وSWT)، يتم استخدام مؤشر ترابط إرسال حدث منفصل (EDT) لفحص أحداث واجهة المستخدم الرسومية. عندما نضغط على زر، سيتم استدعاء وظيفة حدث النقر على الزر في سلسلة إرسال الحدث هذه. نظرًا لأن مهمة EDT هي فقط فحص أحداث واجهة المستخدم الرسومية، فإن الاستجابة للأحداث بهذه الطريقة تكون سريعة جدًا.
5. وفورات في التكاليف
هناك بشكل عام ثلاث طرق لتحسين كفاءة تنفيذ البرنامج:
(1) زيادة عدد وحدات المعالجة المركزية في الكمبيوتر.
(2) بدء عمليات متعددة لبرنامج واحد
(3) استخدام عمليات متعددة في البرنامج.
الطريقة الأولى هي الأسهل، ولكنها أيضًا الأكثر تكلفة. ولا تتطلب هذه الطريقة تعديل البرنامج، ومن الناحية النظرية، يمكن لأي برنامج استخدام هذه الطريقة لتحسين كفاءة التنفيذ. على الرغم من أن الطريقة الثانية لا تتطلب شراء أجهزة جديدة، إلا أنه ليس من السهل مشاركة البيانات. إذا كانت المهمة التي سيكملها هذا البرنامج تتطلب مشاركة البيانات، فإن هذه الطريقة ليست مناسبة، وسيستهلك بدء سلاسل عمليات متعددة الكثير من النظام. موارد. الطريقة الثالثة تعوض فقط عيوب الطريقة الأولى، مع وراثة مزاياها. بمعنى آخر، ليست هناك حاجة لشراء وحدة المعالجة المركزية، ولن تشغل الكثير من موارد النظام عن طريق بدء عدد كبير جدًا من سلاسل العمليات (افتراضيًا، مساحة الذاكرة التي يشغلها خيط أصغر بكثير من مساحة الذاكرة التي تشغلها العملية) متعددة)، ويمكن للخيوط المتعددة محاكاة وضع التشغيل لوحدات المعالجة المركزية المتعددة، لذلك فإن استخدام الخيوط المتعددة هو أرخص وسيلة لتحسين كفاءة تنفيذ البرنامج.
3. نموذج موضوع جافا
نظرًا لأن Java هي لغة موجهة للكائنات بحتة، فإن نموذج ترابط Java هو أيضًا موجه للكائنات. تقوم Java بتغليف جميع الوظائف الضرورية لسلاسل الرسائل من خلال فئة Thread. لإنشاء مؤشر ترابط، يجب أن تكون هناك وظيفة تنفيذ مؤشر ترابط. تتوافق وظيفة تنفيذ مؤشر الترابط هذه مع طريقة التشغيل لفئة مؤشر الترابط. تحتوي فئة Thread أيضًا على طريقة بدء، وهي المسؤولة عن إنشاء سلسلة رسائل، وهو ما يعادل استدعاء وظيفة إنشاء سلسلة رسائل Windows CreateThread. عند استدعاء طريقة البدء، إذا تم إنشاء مؤشر الترابط بنجاح، فسيتم استدعاء طريقة التشغيل لفئة الموضوع تلقائيًا. لذلك، يمكن لأي فئة Java ترث Thread إنشاء سلسلة رسائل من خلال طريقة البدء لفئة Thread. إذا كنت تريد تشغيل وظيفة تنفيذ مؤشر الترابط الخاصة بك، فيجب عليك تجاوز طريقة التشغيل لفئة مؤشر الترابط.
بالإضافة إلى فئة Thread في نموذج مؤشر ترابط Java، هناك أيضًا واجهة قابلة للتشغيل تحدد ما إذا كان يمكن استخدام فئة Java كفئة مؤشر ترابط. تحتوي هذه الواجهة على طريقة مجردة واحدة فقط للتشغيل، وهي وظيفة تنفيذ مؤشر الترابط في Java نموذج الخيط. لذلك، فإن المعيار الوحيد لفئة مؤشر الترابط هو ما إذا كانت الفئة تطبق طريقة التشغيل للواجهة القابلة للتشغيل. وبعبارة أخرى، فإن الفئة التي تحتوي على وظيفة تنفيذ مؤشر الترابط هي فئة مؤشر ترابط.
كما يتبين مما سبق، هناك طريقتان لإنشاء سلاسل رسائل في Java، إحداهما هي وراثة فئة Thread، والأخرى هي تنفيذ واجهة Runnable وإنشاء سلاسل رسائل من خلال Thread والفئة التي تنفذ Runnable. يُقال أن هاتين الطريقتين هما في الأساس طريقة، أي أنه يتم إنشاء مؤشر الترابط من خلال فئة الموضوع ويتم تشغيل طريقة التشغيل. لكن الاختلاف الكبير بينهما هو أن سلاسل الرسائل يتم إنشاؤها عن طريق وراثة فئة Thread. على الرغم من أنها أسهل في التنفيذ، نظرًا لأن Java لا تدعم الوراثة المتعددة، إذا ورثت فئة مؤشر الترابط هذه فئات أخرى، لذلك يوفر نموذج ترابط Java طرق إنشاء سلاسل الرسائل من خلال تنفيذ واجهة قابلة للتشغيل، بحيث يمكن لفئات سلاسل الرسائل أن ترث الفئات المتعلقة بالأعمال بدلاً من فئة سلاسل المحادثات عند الضرورة.