परिचय: C++ में कार्य कतारों की आवश्यकता क्यों है?
\n\nआधुनिक प्रोग्रामिंग में, विशेष रूप से मल्टीथ्रेडेड अनुप्रयोगों के साथ काम करते समय, कार्यों को उनके आगमन के क्रम में व्यवस्थित करने की आवश्यकता अक्सर उत्पन्न होती है। कार्य कतारें (task queues) एक मौलिक पैटर्न हैं जो थ्रेड्स के बीच कार्य को कुशलतापूर्वक वितरित करने, वेब सर्वर अनुरोधों को संसाधित करने, पृष्ठभूमि प्रक्रियाओं को प्रबंधित करने और रेस कंडीशन से बचने की अनुमति देता है।
\n\nC++ में, मानक लाइब्रेरी एक शक्तिशाली कंटेनर std::queue प्रदान करती है जो कार्य कतारों को लागू करने के लिए आदर्श है। हालांकि, व्यवहार में केवल तत्वों को संग्रहीत करना ही नहीं, बल्कि उन्हें थ्रेड्स के बीच सुरक्षित रूप से स्थानांतरित करना, त्रुटियों को संभालना और कार्यों के जीवनचक्र का प्रबंधन करना आवश्यक है। इस लेख में, हम भाषा की आधुनिक क्षमताओं (C++11 और नए) का उपयोग करके C++ में कार्य कतारों को शुरू से बनाने का तरीका समझेंगे।
हम निम्नलिखित पर विचार करेंगे:
\n- \n
std::queueके साथ बुनियादी कार्य \n - थ्रेड-सुरक्षित कार्य कतार \n
- थ्रेड पूल (thread pool) का कार्यान्वयन \n
- प्राथमिकता कतारें \n
1. std::queue के साथ बुनियादी कार्य कतार
\n\nएक सरल उदाहरण से शुरू करते हैं। std::queue एक कंटेनर-एडेप्टर है जो FIFO (First In, First Out) सिद्धांत पर काम करता है। यह push(), pop(), front() और empty() विधियाँ प्रदान करता है।
यहां बताया गया है कि कैसे एक कार्य कतार को व्यवस्थित किया जा सकता है, जहां प्रत्येक कार्य एक फ़ंक्शन (या कॉल करने योग्य ऑब्जेक्ट) है:
\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\n2. थ्रेड-सुरक्षित कार्य कतार
\n\nकतार को मल्टीथ्रेडेड एक्सेस के लिए सुरक्षित बनाने के लिए, हम म्यूटेक्स (std::mutex) और कंडीशनल वेरिएबल (std::condition_variable) का उपयोग करते हैं। यह क्लासिक producer-consumer (उत्पादक-उपभोक्ता) पैटर्न है।
थ्रेड-सुरक्षित कतार का कार्यान्वयन:
\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