C++ में समवर्तीता और मल्टीथ्रेडिंग: उन्नत स्तर

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

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

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

C++ में समवर्तीता और मल्टीथ्रेडिंग: उन्नत स्तर

\n\n

आधुनिक अनुप्रयोगों को अधिकतम प्रदर्शन की आवश्यकता होती है, और C++ में मल्टीथ्रेडिंग इसे प्राप्त करने के लिए प्रमुख उपकरणों में से एक है। हालाँकि, बुनियादी तंत्र (std::thread, std::mutex) अक्सर ब्लॉकिंग, डेटा रेस और दक्षता में कमी का कारण बनते हैं। इस लेख में, हम C++ में समवर्तीता के साथ काम करने की उन्नत तकनीकों पर चर्चा करेंगे: परमाणु संक्रियाओं से लेकर lock-free डेटा संरचनाओं और एसिंक्रोनस कार्यों तक।

\n\n

1. परमाणु संक्रियाएँ और memory ordering

\n\n

क्लासिकल म्यूटेक्स एक भारी तंत्र हैं। सरल काउंटर या फ्लैग के लिए std::atomic का उपयोग करना बेहतर है। यह बिना लॉक के पढ़ने/लिखने की परमाणुता की गारंटी देता है। हालाँकि, उन्नत स्तर पर memory ordering को समझना महत्वपूर्ण है - C++ मेमोरी मॉडल, जो थ्रेड्स के बीच परिवर्तनों की दृश्यता निर्धारित करता है।

\n\n

मुख्य मेमोरी ऑर्डर:

\n
    \n
  • memory_order_relaxed — न्यूनतम गारंटी, केवल परमाणुता।
  • \n
  • memory_order_consume — शायद ही कभी उपयोग किया जाता है, डेटा पर निर्भर करता है।
  • \n
  • memory_order_acquire — इस संक्रिया से पहले सभी बाद के पढ़ने/लिखने को पुनः क्रमबद्ध नहीं किया जा सकता।
  • \n
  • memory_order_release — इस संक्रिया के बाद सभी पिछले लेखन अन्य थ्रेड्स को दिखाई देने लगते हैं।
  • \n
  • memory_order_acq_rel — acquire और release का संयोजन।
  • \n
  • memory_order_seq_cst — सबसे सख्त, वैश्विक अनुक्रमिक स्थिरता (डिफ़ॉल्ट)।
  • \n
\n\n

उपयोग का उदाहरण:

\n
#include <atomic>\n#include <thread>\n#include <cassert>\n\nstd::atomic<bool> ready{false};\nint data = 0;\n\nvoid producer() {\n    data = 42;                                   // डेटा लिखना\n    ready.store(true, std::memory_order_release); // फ्लैग प्रकाशित करना\n}\n\nvoid consumer() {\n    while (!ready.load(std::memory_order_acquire)) // फ्लैग की प्रतीक्षा\n        ;\n    assert(data == 42); // गारंटी है कि data == 42 दिखेगा\n}\n\nint main() {\n    std::thread t1(producer);\n    std::thread t2(consumer);\n    t1.join();\n    t2.join();\n    return 0;\n}
\n\n

यहाँ release और acquire गारंटी देते हैं कि data का लेखन फ्लैग सेट करने से पहले होगा, और पढ़ना बाद में होगा। यह म्यूटेक्स से तेज़ है।

\n\n

2. Lock-free डेटा संरचनाएँ

\n\n

Lock-free एल्गोरिदम परमाणु संक्रियाओं और CAS (Compare-And-Swap) का उपयोग करके ब्लॉकिंग से बचते हैं। एक क्लासिकल उदाहरण एकल-लिंक्ड सूची पर आधारित lock-free स्टैक है।

\n\n

Lock-free स्टैक का कार्यान्वयन:

\n
#include <atomic>\n#include <memory>\n\ntemplate<typename T>\nclass LockFreeStack {\nprivate:\n    struct Node {\n        T data;\n        Node* next;\n        Node(const T& val) : data(val), next(nullptr) {}\n    };\n    std::atomic<Node*> head{nullptr};\n\npublic:\n    void push(const T& val) {\n        Node* new_node = new Node(val);\n        new_node->next = head.load(std::memory_order_relaxed);\n        while (!head.compare_exchange_weak(\n            new_node->next, new_node,\n            std::memory_order_release,\n            std::memory_order_relaxed)) {\n            // लूप, जब तक CAS सफल न हो जाए\n        }\n    }\n\n    bool pop(T& result) {\n        Node* old_head = head.load(std::memory_order_relaxed);\n        while (old_head != nullptr &&\n               !head.compare_exchange_weak(\n                   old_head, old_head->next,\n                   std::memory_order_acquire,\n                   std::memory_order_relaxed)) {\n            // प्रतीक्षा\n        }\n        if (old_head == nullptr) return false;\n        result = old_head->data;\n        // ध्यान दें: वास्तविक कोड में कचरा संग्रहक या hazard pointers की आवश्यकता है\n        delete old_head;\n        return true;\n    }\n};
\n\n

महत्वपूर्ण टिप्पणियाँ:

\n
    \n

ब्लॉग

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