قوائم المهام لـ C++: التنفيذ والاستخدام

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

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

ابدأ الدورة

قوائم المهام لـ C++: من النظرية إلى التطبيق



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



لماذا نحتاج إلى قائمة مهام؟

في التطبيقات الحديثة، غالباً ما تنشأ الحاجة لتنفيذ العديد من المهام الصغيرة بالتوازي. يؤدي الإنشاء المباشر للخيوط لكل مهمة إلى تكاليف إضافية: إنشاء الخيط يستغرق وقتاً وذاكرة. تحل قائمة المهام هذه المشكلة من خلال تجمع الخيوط (thread pool):

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


التنفيذ الأساسي لقائمة المهام في C++

لننظر إلى قائمة مهام بسيطة ولكنها آمنة للخيوط باستخدام std::queue وكائنات المزامنة (mutexes). لهذا، نستخدم المكتبة القياسية C++11 وما فوق.



#include <queue>#include <mutex>#include <condition_variable>#include <functional>#include <thread>#include <vector>

class TaskQueue {public: using Task = std::function<void()>;

explicit TaskQueue(size_t numThreads) : stop(false) { for (size_t i = 0; i < numThreads; ++i) { workers.emplace_back([this] { workerLoop(); }); } }

~TaskQueue() { { std::unique_lock<std::mutex> lock(mutex); stop = true; } condition.notify_all(); for (auto& worker : workers) { if (worker.joinable()) { worker.join(); } } }

void enqueue(Task task) { { std::unique_lock<std::mutex> lock(mutex); tasks.push(std::move(task)); } condition.notify_one(); }

private: void workerLoop() { while (true) { Task task; { std::unique_lock<std::mutex> lock(mutex); condition.wait(lock, [this] { return stop || !tasks.empty(); }); if (stop && tasks.empty()) { return; } task = std::move(tasks.front()); tasks.pop(); } task(); // تنفيذ المهمة } }

std::queue<Task> tasks; std::mutex mutex; std::condition_variable condition; bool stop; std::vector<std::thread> workers;};


مثال على الاستخدام

الآن سنعرض كيفية استخدام الفئة TaskQueue الخاصة بنا لتنفيذ عمليات حسابية بسيطة بالتوازي:



#include <iostream>

int main() { TaskQueue tq(4); // تجمع من 4 خيوط

for (int i = 0; i < 10; ++i) { tq.enqueue([i] { std::cout << "المهمة " << i << " تم تنفيذها بواسطة الخيط " << std::this_thread::get_id() << std::endl; }); }

// المدمر tq سينتظر اكتمال جميع المهام return 0;}


إمكانيات متقدمة: قائمة مهام ذات أولوية

في بعض الأحيان، يلزم معالجة المهام حسب أهميتها. لهذا، يمكن استخدام std::priority_queue بدلاً من القائمة العادية. دعنا نضيف دعم الأولويات:



#include <queue>#include <functional>

class PriorityTaskQueue {public: using Task = std::function<void()>;

struct PrioritizedTask { int priority; Task t

توصيات