قوائم المهام في C++: دليل عملي مع أمثلة

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

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

ابدأ الدورة

مقدمة: لماذا نحتاج قوائم المهام في C++؟

\n\n

في البرمجة الحديثة، خاصة عند العمل مع التطبيقات متعددة الخيوط، غالبًا ما تنشأ الحاجة إلى تنظيم تنفيذ المهام بترتيب وصولها. قوائم المهام (task queues) هي نمط أساسي يسمح بتوزيع العمل بكفاءة بين الخيوط، ومعالجة طلبات خوادم الويب، وإدارة العمليات الخلفية، وتجنب حالات السباق (race conditions).

\n\n

في C++، توفر المكتبة القياسية حاوية قوية std::queue، وهي مثالية لتنفيذ قوائم المهام. ومع ذلك، من الناحية العملية، لا يكفي مجرد تخزين العناصر، بل يجب نقلها بأمان بين الخيوط، ومعالجة الأخطاء، وإدارة دورة حياة المهام. في هذه المقالة، سنشرح كيفية إنشاء قوائم مهام في C++ من الصفر، باستخدام إمكانيات اللغة الحديثة (C++11 والإصدارات الأحدث).

\n\n

سنناقش:

\n
    \n
  • العمل الأساسي مع std::queue
  • \n
  • قائمة مهام آمنة للخيوط
  • \n
  • تنفيذ مجموعة خيوط (thread pool)
  • \n
  • قوائم ذات أولوية
  • \n
\n\n

1. قائمة مهام أساسية باستخدام std::queue

\n\n

لنبدأ بمثال بسيط. std::queue هي حاوية محوّلة تعمل وفق مبدأ FIFO (أول من يدخل، أول من يخرج). توفر طرق push() و pop() و front() و empty().

\n\n

إليك كيفية تنظيم قائمة مهام حيث كل مهمة هي دالة (أو كائن قابل للاستدعاء):

\n\n
#include <iostream>\n#include <queue>\n#include <functional>\n\nint main() {\n    // قائمة مهام، حيث كل مهمة هي std::function<void()>\n    std::queue<std::function<void()>> taskQueue;\n\n    // إضافة المهام\n    taskQueue.push([]() { std::cout << "تم تنفيذ المهمة 1\\n"; });\n    taskQueue.push([]() { std::cout << "تم تنفيذ المهمة 2\\n"; });\n    taskQueue.push([]() { std::cout << "تم تنفيذ المهمة 3\\n"; });\n\n    // معالجة القائمة\n    while (!taskQueue.empty()) {\n        auto task = taskQueue.front();\n        task();  // تنفيذ المهمة\n        taskQueue.pop();  // حذف المهمة المنفذة\n    }\n\n    return 0;\n}
\n\n

يعمل هذا الكود، ولكن فقط في وضع الخيط الواحد. إذا قامت عدة خيوط بإضافة أو استخراج المهام في وقت واحد، فسينشأ حالة سباق. لتعدد الخيوط، نحتاج إلى مزامنة.

\n\n

2. قائمة مهام آمنة للخيوط

\n\n

لجعل القائمة آمنة للوصول متعدد الخيوط، نستخدم كائن المزامنة (std::mutex) والمتغير الشرطي (std::condition_variable). هذا هو النمط الكلاسيكي للمنتج-المستهلك (producer-consumer).

\n\n

تنفيذ قائمة مهام آمنة للخيوط:

\n\n
#include <queue>\n#include <mutex>\n#include <condition_variable>\n#include <functional>\n#include <thread>\n\nclass ThreadSafeQueue {\nprivate:\n    std::queue<std::function<void()>> queue_;\n    std::mutex mutex_;\n    std::condition_variable cond_;\n    bool stop_ = false;\n\npublic:\n    void push(std::function<void()> task) {\n        std::lock_guard<std::mutex> lock(mutex_);\n        queue_.push(task);\n        cond_.notify_one();  // إخطار خيط واحد منتظر\n    }\n\n    std::function<void()> pop() {\n        std::unique_lock<std::mutex> lock(mutex_);\n        cond_.wait(lock, [this]() { return !queue_.empty() || stop_; });\n        if (stop_ && queue_.empty()) {\n            return nullptr;  // إشارة إيقاف\n        }\n        auto task = queue_.front();\n        queue_.pop();\n        return task;\n    }\n\n    void stop() {\n        std::lock_guard<std::mutex> lock(mutex_);\n        stop_ = true;\n        cond_.notify_all();  // إيقاظ جميع الخيوط للإنهاء\n    }\n};
\n\n

النقاط الرئيسية:

\n
    \n
  • std::lock_gu

المدونات

توصيات الكتب