C++ में कार्य कतारें: कार्यान्वयन, अनुप्रयोग और अनुकूलन

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

C++ में कार्य कतारों के साथ काम करना: सरल से जटिल तक



C++ में आधुनिक विकास में शायद ही कभी अतुल्यकालिक डेटा प्रसंस्करण के बिना काम चलता है। कार्य कतारें (task queues) समानांतर कोड निष्पादन को व्यवस्थित करने के लिए प्रमुख उपकरणों में से एक हैं। वे थ्रेड्स के बीच काम वितरित करने, ब्लॉकिंग से बचने और प्रोसेसर संसाधनों का कुशलतापूर्वक उपयोग करने की अनुमति देते हैं। इस लेख में, हम C++ में कार्य कतार को लागू करने का तरीका समझेंगे, producer-consumer पैटर्न पर विचार करेंगे और एक सरल thread pool बनाना सीखेंगे।



1. std::queue पर आधारित मूल कतार



सबसे सरल कार्य कतार एक कंटेनर है जिसमें तत्वों (कार्यों) को जोड़ा जा सकता है और उन्हें FIFO क्रम में निकाला जा सकता है। C++ में, इसके लिए मानक लाइब्रेरी का std::queue एकदम उपयुक्त है। हालांकि, मल्टीथ्रेडिंग के साथ काम करते समय, एक सामान्य कतार असुरक्षित होती है: विभिन्न थ्रेड्स से एक साथ पहुंच डेटा रेस की ओर ले जाती है।



म्यूटेक्स और कंडीशन वेरिएबल का उपयोग करके सिंक्रनाइज़ कतार का एक बुनियादी उदाहरण देखें:



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

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

void push(Task task) { std::lock_guard<std::mutex> lock(mutex_); queue_.push(std::move(task)); cond_var_.notify_one(); }

Task pop() { std::unique_lock<std::mutex> lock(mutex_); cond_var_.wait(lock, [this]() { return !queue_.empty(); }); Task task = std::move(queue_.front()); queue_.pop(); return task; }

bool empty() const { std::lock_guard<std::mutex> lock(mutex_); return queue_.empty(); }

private: std::queue<Task> queue_; mutable std::mutex mutex_; std::condition_variable cond_var_;};


इस कोड में, push() एक कार्य जोड़ता है और एक प्रतीक्षा कर रहे थ्रेड को सूचित करता है। pop() थ्रेड को तब तक ब्लॉक करता है जब तक कतार खाली न हो जाए। यह दृष्टिकोण सिंक्रनाइज़ेशन समस्या को हल करता है, लेकिन संशोधनों के बिना कई उपभोक्ताओं पर स्केल नहीं होता है।



2. Producer-Consumer पैटर्न



क्लासिक producer-consumer (उत्पादक-उपभोक्ता) समस्या कार्य कतार पर पूरी तरह से फिट बैठती है। एक या अधिक उत्पादक थ्रेड कार्य उत्पन्न करते हैं, और उपभोक्ता थ्रेड उन्हें निष्पादित करते हैं। ओवरफ्लो या निष्क्रियता से बचने के लिए कतार के आकार को ठीक से प्रबंधित करना महत्वपूर्ण है।



कई उपभोक्ताओं के साथ उदाहरण:



#include <thread>#include <vector>#include <iostream>

void worker(TaskQueue& queue, int id) { while (true) { auto task = queue.pop(); if (!task) break; // समाप्ति संकेत std::cout << "Worker " << id << " executing task"; task(); }}

int main() { TaskQueue queue; std::vector<std::thread> workers;

// 4 उपभोक्ता थ्रेड शुरू करें for (int i = 0; i < 4; ++i) { workers.emplace_back(worker, std::ref(queue), i); }

// उत्पादक कार्य जोड़ता है for (int i = 0; i < 10; ++i) { queue.push([i]() { std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::cout << "Task " << i << " done"; }); }

// समाप्ति संकेत (nullptr कार्य) for (auto& w : workers) { queue.push(nullptr); }

for (auto& w : workers) { w.join(); } return 0;}


यहां, प्रत्येक उपभोक्ता एक कार्य प्राप्त करता है, उसे निष्पादित करता है और अगले की प्रतीक्षा करता है। समाप्ति संकेत (nullptr) लूप को रोकता है। इस पैटर्न का उपयोग अक्सर सर्वर अनुप्रयोगों, इवेंट हैंडलर और गेम इंजन में किया जाता है।



3. Thread Pool — कार्य कतार के लिए थ्रेड पूल



Thread pool (थ्रेड पूल) कार्य कतार के ऊपर एक ओवरले है जो प्रबंधन करता है

ब्लॉग

पुस्तक अनुशंसाएँ