التزامن وتعدد الخيوط في C#: من الألف إلى الياء — دليل كامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا نحتاج التزامن في C#؟

تتطلب التطبيقات الحديثة بشكل متزايد تنفيذ عدة عمليات في وقت واحد. يتوقع المستخدم ألا "يتجمد" واجهة المستخدم عند تحميل البيانات، وأن يتمكن الخادم من معالجة آلاف الطلبات بالتوازي. في C# (.NET) لحل هذه المشكلات، نستخدم التزامن — قدرة البرنامج على تنفيذ مهام متعددة في فترات زمنية متداخلة، وتعدد الخيوط — تنفيذ التزامن باستخدام عدة خيوط تنفيذ.

في هذه المقالة، سنناقش المفاهيم الأساسية: من Thread الأساسي إلى async/await وParallel الحديثة. ستتعلم كيفية اختيار الأداة المناسبة لكل مهمة وتجنب الأخطاء الشائعة مثل حالات الجمود (deadlocks) وسباقات البيانات (race conditions).



1. الأساسيات: Thread وThreadPool

العمل مع الخيوط عبر Thread

فئة System.Threading.Thread هي الطريقة الأكثر انخفاضاً في المستوى لإنشاء الخيوط. كل خيط له مكدس خاص به ويتم تنفيذه بشكل مستقل. مثال على إنشاء وتشغيل خيط:

using System;using System.Threading;

class Program{ static void Main() { Thread thread = new Thread(DoWork); thread.Start(); // الخيط الرئيسي يواصل العمل for (int i = 0; i < 5; i++) { Console.WriteLine($"الخيط الرئيسي: {i}"); Thread.Sleep(100); } thread.Join(); // انتظار انتهاء الخيط الفرعي }

static void DoWork() { for (int i = 0; i < 5; i++) { Console.WriteLine($"خيط العمل: {i}"); Thread.Sleep(150); } }}

هام: إنشاء خيط جديد عملية مكلفة. للإنشاء المتكرر للخيوط قصيرة العمر، من الأفضل استخدام ThreadPool.



ThreadPool — تجمع الخيوط

ThreadPool يدير مجموعة من خيوط العمل التي يتم إعادة استخدامها. هذا أكثر كفاءة من إنشاء Thread يدوياً. مثال:

ThreadPool.QueueUserWorkItem(state =>{    Console.WriteLine("المهمة تُنفذ في تجمع الخيوط");    Thread.Sleep(500);    Console.WriteLine("المهمة اكتملت");});

Console.WriteLine("الخيط الرئيسي يواصل العمل");Console.ReadKey();

قيود: لا يمكنك التحكم مباشرة في أولوية أو اسم الخيط من التجمع. للتحكم الدقيق، استخدم Task.



2. Task ومكتبة المهام المتوازية (TPL)

Task — النهج الحديث

بدءاً من .NET 4.0، أصبح Task الأداة الرئيسية للعمليات غير المتزامنة. يقوم بتجريد الخيوط ويسمح بالعمل مع نتائج التنفيذ. مثال:

using System;using System.Threading.Tasks;

class Program{ static async Task Main() { Task<int> task = Task.Run(() => ComputeResult(10)); // يمكن القيام بعمل آخر Console.WriteLine("في انتظار النتيجة..."); int result = await task; Console.WriteLine($"النتيجة: {result}"); }

static int ComputeResult(int value) { Task.Delay(1000).Wait(); // محاكاة عملية طويلة return value * 2; }}

المزايا الرئيسية:

  • إرجاع النتيجة عبر Task<T>
  • دعم الإلغاء عبر CancellationToken
  • إمكانية دمج المهام (ContinueWith, WhenAll, WhenAny)
  • متكامل مع async/await


Parallel — للحلقات المتوازية

فئة Parallel تبسط تنفيذ الحلقات مع التوازي. مثال:

using System;using System.Threading.Tasks;

class Program{ static void Main()\

المدونات

توصيات الكتب