مقدمة: لماذا نحتاج إلى قوائم المهام في C#؟
تخيل أنك تقوم بتطوير تطبيق يعالج الطلبات في متجر إلكتروني. يرسل العملاء الطلبات في وقت واحد، وكل طلب يتطلب وقتًا (مثل التحقق من الدفع أو إرسال بريد إلكتروني). إذا تمت معالجتها بشكل تسلسلي، فسيتباطأ التطبيق وسينتظر المستخدمون. الحل هو استخدام قائمة المهام.
قائمة المهام (Task Queue) هي بنية بيانات تعمل وفق مبدأ FIFO (First In, First Out - "من يدخل أولاً يخرج أولاً"). في C# (.NET)، تم تنفيذ قوائم المهام بعدة أشكال: من البسيطة Queue<T> إلى الآمنة للخيوط ConcurrentQueue<T>. في هذه المقالة، سنشرح كيفية إنشاء قوائم المهام، وإضافة واستخراج المهام، وكذلك كيفية استخدامها في البرمجة غير المتزامنة.
المقالة موجهة للمبتدئين، لذلك سنبدأ بالأساسيات ثم ننتقل تدريجياً إلى أمثلة أكثر تعقيدًا.
1. أساسيات العمل مع Queue<T> في C#
توجد الفئة Queue<T> في مساحة الأسماء System.Collections.Generic. وهي قائمة مهام بسيطة لا تدعم تعدد الخيوط - يجب استخدامها فقط في السيناريوهات أحادية الخيط.
إنشاء قائمة المهام والعمليات الأساسية
لنقم بإنشاء قائمة مهام لتخزين المهام النصية:
using System;using System.Collections.Generic;
class Program{ static void Main() { // إنشاء قائمة مهام من النصوص Queue<string> taskQueue = new Queue<string>();
// إضافة المهام (Enqueue) taskQueue.Enqueue("إرسال بريد إلكتروني للعميل"); taskQueue.Enqueue("التحقق من حالة الطلب"); taskQueue.Enqueue("تحديث قاعدة البيانات");
Console.WriteLine($"عدد المهام: {taskQueue.Count}");
// استخراج مهمة (Dequeue) - يزيل ويعيد العنصر الأول string firstTask = taskQueue.Dequeue(); Console.WriteLine($"جارٍ تنفيذ: {firstTask}");
// عرض المهمة التالية دون إزالتها (Peek) string nextTask = taskQueue.Peek(); Console.WriteLine($"المهمة التالية: {nextTask}");
Console.WriteLine($"المهام المتبقية: {taskQueue.Count}"); }}مخرجات البرنامج:
عدد المهام: 3جارٍ تنفيذ: إرسال بريد إلكتروني للعميلالمهمة التالية: التحقق من حالة الطلبالمهام المتبقية: 2الطرق الهامة لـ Queue<T>
Enqueue(item)- يضيف عنصرًا إلى نهاية قائمة المهام.Dequeue()- يزيل ويعيد العنصر الأول. إذا كانت قائمة المهام فارغة، فإنه يلقي استثناءInvalidOperationException.Peek()- يعيد العنصر الأول دون إزالته.Clear()- يمسح قائمة المهام.Contains(item)- يتحقق مما إذا كان العنصر موجودًا في قائمة المهام.
هام: Queue<T> ليست آمنة للخيوط. إذا قامت عدة خيوط بإضافة أو استخراج عناصر في نفس الوقت، فستحدث أخطاء. للسيناريوهات متعددة الخيوط، استخدم ConcurrentQueue<T>.
2. قائمة المهام الآمنة للخيوط: ConcurrentQueue<T>
في التطبيقات الواقعية، غالبًا ما تتم إضافة المهام ومعالجتها في خيوط مختلفة. لهذا الغرض، توجد في .NET فئة ConcurrentQueue<T> من مساحة الأسماء System.Collections.Concurrent.
مثال: Producer-Consumer (منتج-مستهلك)
تخيل أن خيطًا واحدًا (Producer) يولد المهام، بينما خيط آخر (Consumer) ينفذها.
using System;using System.Collections.Concurrent;using System.Threading.Tasks;
class Program{ static void Main() { ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
// المنتج: يضيف المهام