C++ में समवर्तीता और मल्टीथ्रेडिंग: मूल बातों से उन्नत तकनीकों तक
आधुनिक अनुप्रयोगों को तेजी से अधिकतम प्रदर्शन की आवश्यकता होती है, विशेष रूप से मल्टी-कोर प्रोसेसर के साथ काम करते समय। C++ C++11 से लेकर नवीनतम मानकों तक, समवर्तीता और मल्टीथ्रेडिंग के लिए शक्तिशाली उपकरण प्रदान करता है। इस लेख में, हम मल्टीथ्रेडिंग के उन्नत पहलुओं पर चर्चा करेंगे: म्यूटेक्स और परमाणु संचालन के सही उपयोग से लेकर जटिल सिंक्रनाइज़ेशन पैटर्न तक। यह सामग्री उन डेवलपर्स के लिए है जो पहले से ही C++ में थ्रेड्स की मूल बातों से परिचित हैं।
1. थ्रेड प्रबंधन: std::thread और std::jthread
क्लास std::thread C++ में मल्टीथ्रेडेड प्रोग्रामिंग की नींव है। हालांकि, उन्नत स्तर पर, न केवल एक थ्रेड बनाना महत्वपूर्ण है, बल्कि इसके जीवनचक्र को ठीक से प्रबंधित करना भी महत्वपूर्ण है। C++20 के साथ, std::jthread आया, जो नष्ट होने पर स्वचालित रूप से जुड़ जाता है, संसाधन लीक को रोकता है।
std::jthread का उपयोग करने का उदाहरण:
#include <iostream>#include <thread>#include <chrono>
void worker(int id) { std::this_thread::sleep_for(std::chrono::milliseconds(100 * id)); std::cout << "थ्रेड " << id << " पूर्ण हुआ";}
int main() { // std::jthread दायरे से बाहर निकलने पर स्वचालित रूप से जुड़ जाता है std::jthread t1(worker, 1); std::jthread t2(worker, 2); std::jthread t3(worker, 3); // स्पष्ट रूप से join() या detach() कॉल करने की आवश्यकता नहीं है // t1, t2, t3 के नष्ट होने पर, main उनके पूरा होने की प्रतीक्षा करता है std::cout << "मुख्य थ्रेड काम करता रहता है"; return 0;}यह याद रखना महत्वपूर्ण है: std::jthread std::stop_token के माध्यम से रोक तंत्र का भी समर्थन करता है, जो लंबे समय तक चलने वाले पृष्ठभूमि कार्यों को सुरक्षित रूप से समाप्त करने की अनुमति देता है।
2. एक्सेस सिंक्रनाइज़ेशन: म्यूटेक्स, लॉक और कंडीशनल वेरिएबल
मल्टीथ्रेडिंग की मुख्य समस्या डेटा रेस है। उन्हें रोकने के लिए म्यूटेक्स का उपयोग किया जाता है। उन्नत स्तर पर, डेडलॉक के जोखिम के बिना कई म्यूटेक्स को कैप्चर करने के लिए std::scoped_lock (C++17) का उपयोग करने की अनुशंसा की जाती है।
std::scoped_lock के साथ उदाहरण:
#include <iostream>#include <mutex>#include <thread>#include <vector>
std::mutex mtx1, mtx2;int shared_data = 0;
void safe_increment(int id) { // scoped_lock डेडलॉक से बचने के लिए क्रम में दोनों म्यूटेक्स को कैप्चर करता है std::scoped_lock lock(mtx1, mtx2); ++shared_data; std::cout << "थ्रेड " << id << " ने मान बढ़ाकर " << shared_data << " कर दिया";}
int main() { std::vector<std::jthread> threads; for (int i = 0; i < 10; ++i) { threads.emplace_back(safe_increment, i); } return 0;}अधिक जटिल सिंक्रनाइज़ेशन परिदृश्यों (जैसे, प्रोड्यूसर-कंज़्यूमर) के लिए, कंडीशनल वेरिएबल (std::condition_variable) का उपयोग किया जाता है। वे थ्रेड्स को सक्रिय प्रतीक्षा पर संसाधन खर्च किए बिना किसी विशिष्ट घटना के घटित होने की प्रतीक्षा करने की अनुमति देते हैं।
3. परमाणु संचालन और C++ मेमोरी मॉडल
परमाणु संचालन (std::atomic) लॉक-फ्री प्रोग्रामिंग का आधार हैं। वे गारंटी देते हैं कि एक वेरिएबल का पढ़ना और लिखना एक एकल अविभाज्य क्रिया के रूप में निष्पादित किया जाएगा। हालांकि, उन्नत स्तर पर, C++ मेमोरी मॉडल और मेमोरी ऑर्डरिंग के स्तरों को समझना महत्वपूर्ण है।
मेमोरी ऑर्डरिंग के मुख्य स्तर:
memory_order_relaxed— न्यूनतम गारंटी, केवल परमाणुताmemory_order_acquire— गारंटी देता है कि सभी बाद के पढ़ने और लिखने से पिछले संचालन के परिणाम दिखाई देंगेmemory_order_release— गारंटी देता है कि सभी पिछले संचालन इस लिखने के बाद दिखाई देंगेmemory_order_acq_rel— acquire और release का संयोजन