मल्टीथ्रेडेड बग्स से ग्रस्त


26

मेरी नई टीम, जिसे मैं प्रबंधित करता हूं, हमारे कोड का अधिकांश प्लेटफ़ॉर्म, टीसीपी सॉकेट और http नेटवर्किंग कोड है। सभी सी ++। इसका अधिकांश हिस्सा अन्य डेवलपर्स से उत्पन्न हुआ, जिन्होंने टीम को छोड़ दिया है। टीम के वर्तमान डेवलपर बहुत स्मार्ट हैं, लेकिन अनुभव के मामले में ज्यादातर जूनियर हैं।

हमारी सबसे बड़ी समस्या: बहु-थ्रेडेड कंसीलर कीड़े। हमारे अधिकांश कक्षा पुस्तकालयों को कुछ थ्रेड पूल कक्षाओं के उपयोग से अतुल्यकालिक लिखा जाता है। कक्षा पुस्तकालयों पर विधियाँ अक्सर एक थ्रेड से थ्रेड पूल पर लंबे समय तक चलने वाली टाँके लगाती हैं और फिर उस कक्षा के कॉलबैक तरीकों को एक अलग धागे पर लागू किया जाता है। नतीजतन, हमारे पास बहुत सारे केस केस बग हैं जिनमें गलत थ्रेडिंग धारणाएं हैं। इसके परिणामस्वरूप सूक्ष्म कीड़े होते हैं जो महत्वपूर्ण अनुभागों से परे जाते हैं और संगामिति मुद्दों से बचाव के लिए लॉक होते हैं।

इन समस्याओं को और भी कठिन बना देता है जिसे ठीक करने का प्रयास अक्सर गलत होता है। कुछ गलतियाँ जो मैंने टीम के प्रयास में देखी हैं (या विरासत कोड के भीतर) निम्नलिखित में से कुछ शामिल हैं:

सामान्य गलती # 1 - केवल साझा किए गए डेटा के चारों ओर लॉक लगाकर समवर्ती समस्या को हल करना, लेकिन जब कोई अपेक्षित क्रम में विधियों को नहीं बुलाया जाता है तो क्या होता है, इसके बारे में भूल जाना। यहाँ एक बहुत ही सरल उदाहरण दिया गया है:

void Foo::OnHttpRequestComplete(statuscode status)
{
    m_pBar->DoSomethingImportant(status);
}

void Foo::Shutdown()
{
    m_pBar->Cleanup();
    delete m_pBar;
    m_pBar=nullptr;
}

तो अब हमारे पास एक बग है जिसमें शटडाउन को बुलाया जा सकता है जबकि OnHttpNetworkRequestComplete चल रहा है। एक परीक्षक बग को ढूंढता है, क्रैश डंप को पकड़ता है, और बग को एक डेवलपर को सौंपता है। वह इस तरह बग को ठीक करता है।

void Foo::OnHttpRequestComplete(statuscode status)
{
    AutoLock lock(m_cs);
    m_pBar->DoSomethingImportant(status);
}

void Foo::Shutdown()
{
    AutoLock lock(m_cs);
    m_pBar->Cleanup();
    delete m_pBar;
    m_pBar=nullptr;
}

उपरोक्त फिक्स तब तक अच्छा लगता है जब तक आपको एहसास न हो कि एक और भी सूक्ष्म किनारे का मामला है। यदि OnHttpRequestComplete को वापस बुलाया जाता है, तो शटडाउन को कॉल करने पर क्या होता है ? मेरी टीम के पास वास्तविक दुनिया के उदाहरण और भी अधिक जटिल हैं, और कोड की समीक्षा प्रक्रिया के दौरान किनारे के मामले और भी कठिन हैं।

कॉमन मिस्टेक # 2 - लॉक से बाहर निकलने के द्वारा डेडलॉक मुद्दों को ठीक करना, दूसरे थ्रेड के समाप्त होने की प्रतीक्षा करें, फिर लॉक को फिर से दर्ज करें - लेकिन इस मामले को हैंडल किए बिना कि ऑब्जेक्ट दूसरे थ्रेड द्वारा अपडेट हो गया है!

कॉमन मिस्टेक # 3 - भले ही ऑब्जेक्ट को रेफरेंस काउंट किया गया हो, शटडाउन सीक्वेंस "पॉइंटर" है। लेकिन उस थ्रेड के लिए इंतजार करना भूल जाता है जो अभी भी जारी करने के लिए चल रहा है। जैसे, घटकों को सफाई से बंद कर दिया जाता है, फिर किसी वस्तु पर स्पुरियस या लेट कॉलबैक किसी भी अधिक कॉल की उम्मीद नहीं करता है।

अन्य किनारे मामले हैं, लेकिन नीचे की रेखा यह है:

मल्टीथ्रेडेड प्रोग्रामिंग सिर्फ सादा कठिन है, स्मार्ट लोगों के लिए भी।

जैसा कि मैं इन गलतियों को पकड़ता हूं, मैं प्रत्येक डेवलपर के साथ त्रुटियों पर चर्चा करने में समय बिताता हूं ताकि एक अधिक उपयुक्त निर्धारण विकसित किया जा सके। लेकिन मुझे संदेह है कि वे अक्सर इस बात पर भ्रमित होते हैं कि प्रत्येक मुद्दे को विरासत कोड की भारी मात्रा में हल करने के कारण "राइट" फिक्स में स्पर्श शामिल होगा।

हम जल्द ही शिपिंग होने जा रहे हैं, और मुझे यकीन है कि हम जो पैच लागू कर रहे हैं वह आगामी रिलीज के लिए होगा। बाद में, हमें कोड बेस और रिफ्लेक्टर को सुधारने के लिए कुछ समय चाहिए। हमारे पास सब कुछ फिर से लिखने का समय नहीं होगा। और कोड के बहुमत यह सब बुरा नहीं है। लेकिन मैं रिफ्लेक्टर कोड को देख रहा हूं ताकि थ्रेडिंग के मुद्दों को पूरी तरह से टाला जा सके।

एक दृष्टिकोण जिस पर मैं विचार कर रहा हूं वह यह है। प्रत्येक महत्वपूर्ण प्लेटफ़ॉर्म सुविधा के लिए, एक समर्पित सिंगल थ्रेड है, जहाँ सभी ईवेंट और नेटवर्क कॉलबैक पर मार्शेल्ड हो जाते हैं। एक संदेश लूप के उपयोग के साथ विंडोज में सूत्रण COM अपार्टमेंट के समान है। लंबे समय तक अवरुद्ध संचालन अभी भी एक कार्य पूल थ्रेड के लिए भेजा जा सकता है, लेकिन घटक के धागे पर पूरा कॉलबैक लागू किया जाता है। घटक संभवतः उसी धागे को साझा भी कर सकते हैं। फिर धागे के अंदर चलने वाले सभी कक्षा पुस्तकालयों को एक एकल पिरोया दुनिया की धारणा के तहत लिखा जा सकता है।

इससे पहले कि मैं उस रास्ते से नीचे जाऊं, मुझे बहुत दिलचस्पी है अगर मल्टीथ्रेडेड मुद्दों से निपटने के लिए अन्य मानक तकनीक या डिज़ाइन पैटर्न हैं। और मुझे जोर देना है - एक किताब से परे कुछ ऐसा जो म्यूटेक्स और सेमाफोर की मूल बातों का वर्णन करता है। तुम क्या सोचते हो?

मैं भी किसी भी अन्य दृष्टिकोण में दिलचस्पी ले रहा हूँ एक refactoring प्रक्रिया की ओर ले जाने के लिए। निम्नलिखित में से कोई भी शामिल है:

  1. धागे के चारों ओर डिजाइन पैटर्न पर साहित्य या कागजात। म्यूटेक्स और सेमाफोरस के परिचय से परे कुछ। हमें बड़े पैमाने पर समानता की आवश्यकता नहीं है, बस किसी ऑब्जेक्ट मॉडल को डिजाइन करने के तरीके ताकि अन्य धागे से अतुल्यकालिक घटनाओं को सही ढंग से संभाल सकें ।

  2. विभिन्न घटकों के थ्रेडिंग को आरेखित करने के तरीके, ताकि इसके लिए समाधानों का अध्ययन और विकास करना आसान हो। (यानी, वस्तुओं और वर्गों के बीच चर्चा के लिए एक यूएमएल समकक्ष)

  3. मल्टीट्रेड कोड वाले मुद्दों पर अपनी विकास टीम को शिक्षित करना।

  4. तुम क्या करोगे?


23
जब कुछ लोग किसी समस्या से जूझते हैं तो मुझे लगता है कि मैं मल्टी थ्रेडिंग का इस्तेमाल करूंगा। अब उनके पास ट्वोलम जांच है
टॉम

20
क्या मेरे लिए अच्छी तरह से काम करने के लिए है अस्थिरता से छुटकारा पाने के लिए जब भी संभव। जब मैं नए मूल्य को पास करने के लिए उत्परिवर्तित वस्तु को बदलते हुए देखता हूं, तो मैं यह प्रतिशोध करने की कोशिश करता हूं कि बदले में बदले हुए मूल्य को धारण करने वाली एक नई अपरिवर्तनीय वस्तु को पारित किया जाए। वस्तु प्रारंभ सुरक्षित रूप से किया जाता है, इस की गारंटी देता है डेटा दौड़ के अभाव - काफी राहत
कुटकी

3
बहु-धागा नरक में आपका स्वागत है। मैं Ada, Occam, C ++ में> 20 साल के लिए मल्टी-थ्रेड / पैरालेल प्रोग्राम लिख रहा हूं। यह कभी भी आसान नहीं होता है, हर चीज के लिए बहुत सावधानी से सोचने की जरूरत होती है, और कोई भी व्यक्ति जो कहता है कि "इसका आसान सिर्फ एक्स करना है" एक मूर्ख है जो वास्तव में समझ नहीं पाता है कि क्या चल रहा है। सौभाग्य।
जल्‍दी से जल्‍द से जल्‍दी

2
यदि आप अच्छी तरह से किया हुआ संगामिति देखना चाहते हैं तो Erlang का उपयोग करें! सच में आप जो चाहते हैं, वह कुछ भी नहीं एक साझा अभिनेता मॉडल है जहां अजीब कोने के मामलों को समाप्त किया जा रहा है।
ज़ाचरी के

3
@DeadMG मैं यह साझा करना चाहूंगा कि साझा राज्य समवर्ती स्वाभाविक रूप से अजीब कोने के मामलों से ग्रस्त है और इससे बचा जाना चाहिए। लेकिन अरे मैंने एर्लांग पर एक किताब लिखी
ज़ाचरी के

जवाबों:


27

आपके कोड में इसके अलावा अन्य महत्वपूर्ण मुद्दे हैं। मैन्युअल रूप से एक पॉइंटर को हटाना? एक cleanupसमारोह बुला ? Owch। इसके अलावा, जैसा कि प्रश्न टिप्पणी में सटीक रूप से कहा गया है, आप अपने लॉक के लिए RAII का उपयोग नहीं करते हैं, जो एक और काफी महाकाव्य असफल है और गारंटी देता है कि जब DoSomethingImportantएक अपवाद फेंकता है, तो भयानक चीजें होती हैं।

यह तथ्य यह है कि यह बहुस्तरीय बग उत्पन्न हो रहा है, बस मूल समस्या का एक लक्षण है- आपके कोड में किसी भी थ्रेडिंग स्थिति में बेहद खराब शब्दार्थ है और आप पूरी तरह से अविश्वसनीय उपकरण और पूर्व-मुहावरों का उपयोग कर रहे हैं। अगर मैं तुम थे, तो मुझे आश्चर्य होगा कि यह एक ही धागे के साथ काम करता है, अकेले चलो।

कॉमन मिस्टेक # 3 - भले ही ऑब्जेक्ट को रेफरेंस गिना जाए, लेकिन शटडाउन सीक्वेंस "पॉइंटर" है। लेकिन उस थ्रेड के लिए इंतजार करना भूल जाता है जो अभी भी जारी करने के लिए चल रहा है। जैसे, घटकों को सफाई से बंद कर दिया जाता है, फिर किसी वस्तु पर स्पुरियस या लेट कॉलबैक किसी भी अधिक कॉल की उम्मीद नहीं करता है।

संदर्भ गणना की पूरी बात यह है कि थ्रेड पहले ही जारी किया जा चुका है । क्योंकि यदि नहीं, तो इसे नष्ट नहीं किया जा सकता क्योंकि धागे में अभी भी एक संदर्भ है।

का उपयोग करें std::shared_ptr। जब सभी थ्रेड्स जारी किए गए हैं (और कोई नहीं , इसलिए, फ़ंक्शन को कॉल किया जा सकता है, क्योंकि उनके पास इसका कोई संकेतक नहीं है), फिर विध्वंसक कहा जाता है। यह सुरक्षित की गारंटी है।

दूसरे, वास्तविक थ्रेडिंग लाइब्रेरी का उपयोग करें, जैसे इंटेल का थ्रेड बिल्डिंग ब्लॉक्स या माइक्रोसॉफ्ट का पैरेलल पैटर्न लाइब्रेरी। अपना खुद का लिखना समय लेने वाला और अविश्वसनीय है और आपका कोड उन थ्रेडिंग विवरणों से भरा है जिनकी इसे आवश्यकता नहीं है। अपने खुद के ताले करना उतना ही बुरा है जितना कि अपना खुद का मेमोरी मैनेजमेंट करना। उन्होंने पहले से ही कई सामान्य-उद्देश्य बहुत उपयोगी थ्रेडिंग मुहावरों को लागू किया है जो आपके उपयोग के लिए सही तरीके से काम करते हैं।


यह एक ठीक उत्तर है, लेकिन वह दिशा नहीं, जिसकी मुझे तलाश थी, क्योंकि यह नमूना कोड के एक टुकड़े का आकलन करने में बहुत अधिक समय व्यतीत करता है, जो सिर्फ सादगी के लिए लिखा गया था (और हमारे उत्पाद में हमारे वास्तविक कोड का प्रतिबिंब नहीं)। लेकिन मैं आपके द्वारा की गई एक टिप्पणी के बारे में उत्सुक हूं - "अविश्वसनीय उपकरण"। एक अविश्वसनीय उपकरण क्या है? आप किन उपकरणों की सलाह देते हैं?
koncurrency

5
@koncurrency: एक अविश्वसनीय उपकरण मैनुअल मेमोरी मैनेजमेंट जैसी चीज है या अपना खुद का सिंक्रोनाइजेशन लिखना जहां सिद्धांत में यह एक समस्या को हल करता है लेकिन वास्तव में यह इतना बुरा है कि आप बहुत बड़ी गलतियों की गारंटी दे सकते हैं और एकमात्र तरीका यह संभवतः समस्या को हल कर सकता है। एक उचित पैमाने पर हाथ डेवलपर के समय के बड़े पैमाने पर और अनुपातहीन निवेश द्वारा होता है- जो कि अभी आपके पास है।
डेडएमजी

9

अन्य पोस्टरों ने अच्छी तरह से टिप्पणी की है कि कोर मुद्दों को ठीक करने के लिए क्या किया जाना चाहिए। यह पोस्ट विरासत कोड को बेहतर तरीके से पेश करने की अधिक तात्कालिक समस्या से संबंधित है जो आपको हर चीज को सही तरीके से फिर से करने के लिए खरीदने के लिए पर्याप्त है। दूसरे शब्दों में, यह चीजों को करने का सही तरीका नहीं है, यह अभी के लिए लंगड़ा करने का एक तरीका है।

प्रमुख घटनाओं को समेकित करने का आपका विचार एक अच्छी शुरुआत है। मैं सभी प्रमुख तुल्यकालन घटनाओं को संभालने के लिए एक एकल प्रेषण धागे का उपयोग करने के लिए इतनी दूर जाऊँगा, जहाँ भी आदेश निर्भरता हो। थ्रेड-सुरक्षित संदेश कतार सेट करें और जहां भी आप वर्तमान में संगामिति संवेदनशील संचालन (आवंटन, क्लीनअप, कॉलबैक, आदि) करते हैं, इसके बजाय उस थ्रेड को एक संदेश भेजें और यह ऑपरेशन करें या ट्रिगर करें। विचार यह है कि यह एक धागा सभी कार्य-इकाई को नियंत्रित करता है, शुरू होता है, रोकता है, आवंटन करता है और सफाई करता है।

प्रेषण धागा आपके द्वारा बताई गई समस्याओं को हल नहीं करता है, यह सिर्फ उन्हें एक स्थान पर समेकित करता है। आपको अभी भी अप्रत्याशित क्रम में होने वाली घटनाओं / संदेशों के बारे में चिंता करनी होगी। महत्वपूर्ण रन-टाइम वाले इवेंट्स को अभी भी अन्य थ्रेड्स पर भेजने की आवश्यकता होगी, इसलिए अभी भी साझा डेटा पर संगामिति के साथ समस्याएँ हैं। इसे कम करने का एक तरीका है कि संदर्भ द्वारा डेटा पास करने से बचें। जब भी संभव हो, प्रेषण संदेशों में डेटा की प्रतिलिपि होनी चाहिए जो प्राप्तकर्ता के स्वामित्व में होगी। (यह डेटा को अपरिवर्तनीय बनाने की रेखाओं के साथ है जिसका दूसरों ने उल्लेख किया है।)

इस प्रेषण दृष्टिकोण का लाभ यह है कि प्रेषण धागे के भीतर आपके पास एक प्रकार का सुरक्षित-आश्रय है जहां आप कम से कम जानते हैं कि कुछ संचालन क्रमिक रूप से हो रहे हैं। नुकसान यह है कि यह एक अड़चन और अतिरिक्त सीपीयू ओवरहेड बनाता है। मेरा सुझाव है कि पहली बार में उन चीजों में से किसी के बारे में चिंता न करें: पहले डिस्पैच थ्रेड में जितना संभव हो उतना घुमाकर सही संचालन के कुछ उपाय प्राप्त करने पर ध्यान केंद्रित करें। फिर कुछ सीपीयू देखें कि सबसे सीपीयू समय क्या हो रहा है और इसे सही मल्टीप्रेडिंग तकनीकों का उपयोग करके डिस्पैच थ्रेड से वापस शिफ्ट करना शुरू करें।

फिर, मैं जो वर्णन कर रहा हूं वह चीजों को करने का सही तरीका नहीं है, लेकिन इसकी एक प्रक्रिया जो आपको वेतन वृद्धि के सही तरीके की ओर ले जा सकती है जो वाणिज्यिक समय सीमा को पूरा करने के लिए काफी छोटा है।


मौजूदा चुनौती के माध्यम से प्राप्त करने के लिए एक उचित, मध्यवर्ती सुझाव के लिए +1।

हां, यह वह दृष्टिकोण है जिसकी मैं जांच कर रहा हूं। आप प्रदर्शन के बारे में अच्छे अंक जुटाते हैं।
koncurrency

एक ही प्रेषण धागे के माध्यम से चीजों को बदलना त्वरित पैच की तरह नहीं लगता है, बल्कि मेरे लिए एक बड़े पैमाने पर रिफ्लेक्टर है।
सेबस्टियन रेडल

8

दिखाए गए कोड के आधार पर, आपके पास डब्ल्यूटीएफ का ढेर है। यह बेहद मुश्किल है अगर असंभव रूप से लिखे गए बहु-थ्रेडेड अनुप्रयोग को ठीक करना असंभव नहीं है। मालिकों को बताएं कि महत्वपूर्ण पुनरावृत्ति के बिना आवेदन कभी विश्वसनीय नहीं होगा। साझा वस्तुओं के साथ बातचीत करने वाले कोड के प्रत्येक बिट का निरीक्षण और पुन: निरीक्षण करने के आधार पर उन्हें एक अनुमान दें। पहले उन्हें निरीक्षण के लिए एक अनुमान दें। तब आप rework के लिए एक अनुमान दे सकते हैं।

जब आप कोड को फिर से काम करते हैं, तो आपको कोड लिखने की योजना बनानी चाहिए ताकि यह सही ढंग से सही हो। यदि आप यह नहीं जानते कि ऐसा कैसे किया जाए, तो ऐसा कोई व्यक्ति खोजें, जो आप करता है, या आप उसी स्थान पर समाप्त हो जाएंगे।


बस अब यह पढ़ो, मेरे जवाब के बाद उठ गया। केवल यह कहना चाहता था कि मुझे परिचयात्मक वाक्य से प्यार है :)
back2dos

7

यदि आपके पास अपना आवेदन वापस करने के लिए समर्पित करने के लिए कुछ समय है, तो मैं आपको सलाह दूंगा कि आप अभिनेता मॉडल (उदाहरण के लिए थेरॉन , कैसाब्लांका , लिबकप्पा , सीएएफ को C ++ कार्यान्वयन के लिए देखें) पर एक नज़र डालें ।

अभिनेता ऐसी वस्तुएं हैं जो समवर्ती रूप से चलती हैं और केवल अतुल्यकालिक संदेश विनिमय का उपयोग करके एक दूसरे के साथ संवाद करती हैं। इसलिए, थ्रेड मैनेजमेंट, म्यूटेक्स, डेडलॉक, आदि की सभी समस्याओं को एक अभिनेता कार्यान्वयन पुस्तकालय द्वारा निपटाया जाता है और आप अपनी वस्तुओं (अभिनेताओं) के व्यवहार को लागू करने पर ध्यान केंद्रित कर सकते हैं, जो लूप को दोहराने के लिए उबलता है

  1. संदेश प्राप्त करें
  2. अभिकलन प्रदर्शन करें
  3. अन्य अभिनेताओं को संदेश भेजें / बनाएँ / मारें।

आपके लिए एक दृष्टिकोण पहले विषय पर कुछ पढ़ना हो सकता है , और संभवतः एक पुस्तकालय या दो पर एक नज़र रखना है कि क्या अभिनेता मॉडल को आपके कोड में एकीकृत किया जा सकता है।

मैं कुछ महीनों से इस परियोजना में इस मॉडल का (एक सरलीकृत संस्करण) उपयोग कर रहा हूं और मैं इस बात से चकित हूं कि यह कितना मजबूत है।


1
स्काला के लिए अक्का पुस्तकालय इस का एक अच्छा कार्यान्वयन है जो बच्चों के मरने पर माता-पिता के अभिनेताओं को मारने के बारे में बहुत कुछ सोचता है। मुझे पता है कि यह C ++ नहीं है, लेकिन एक नज़र के लायक है: akka.io
GlenPeterson

1
@GlenPeterson: धन्यवाद, मुझे पता है कि अक्का के बारे में (जो कि मैं इस समय सबसे दिलचस्प समाधान मानता हूं, और जावा और स्काला दोनों के साथ काम करता है) लेकिन सवाल विशेष रूप से C ++ को संबोधित करता है। अन्यथा कोई घटना एर्लांग पर विचार कर सकता है। मुझे लगता है कि एरलांग में मल्टी-थ्रेडिंग प्रोग्रामिंग के सभी सिरदर्द अच्छे के लिए चले गए हैं। लेकिन शायद अक्का जैसे ढांचे बहुत करीब आते हैं।
जियोर्जियो

"मुझे लगता है कि एरलांग में मल्टी-थ्रेडिंग प्रोग्रामिंग के सभी सिरदर्द अच्छे के लिए चले गए हैं।" मुझे लगता है कि शायद यह थोड़ा ओवरस्टेट है। या अगर सच है, तो प्रदर्शन में कमी हो सकती है। मुझे पता है कि अक्का सी ++ के साथ काम नहीं करता है, यह कहते हुए कि यह कई धागों के प्रबंधन के लिए अत्याधुनिक है। यह, हालांकि, धागा-सुरक्षित नहीं है। आप अभी भी अभिनेताओं के बीच उत्परिवर्तित अवस्था को पार कर सकते हैं और अपने आप को पैर में मार सकते हैं।
ग्लेनपेटर्सन

मैं एर्लांग विशेषज्ञ नहीं हूं लेकिन AFAIK प्रत्येक अभिनेता को अलगाव में निष्पादित किया जाता है और अपरिवर्तनीय संदेशों का आदान-प्रदान किया जाता है। तो आपको वास्तव में थ्रेड्स और साझा किए जाने योग्य राज्य से निपटने की आवश्यकता नहीं है। प्रदर्शन संभवतः C ++ से कम है, लेकिन यह हमेशा तब होता है जब आप अमूर्त स्तर को बढ़ाते हैं (आप निष्पादन समय बढ़ाते हैं लेकिन विकास के समय को कम करते हैं)।
जियोर्जियो

क्या डाउनवॉटर एक टिप्पणी छोड़ सकता है और सुझाव दे सकता है कि मैं इस उत्तर को कैसे सुधार सकता हूं?
जियोर्जियो

6

सामान्य गलती # 1 - केवल साझा किए गए डेटा के चारों ओर लॉक लगाकर समवर्ती समस्या को हल करना, लेकिन जब कोई अपेक्षित क्रम में विधियों को नहीं बुलाया जाता है तो क्या होता है, इसके बारे में भूल जाना। यहाँ एक बहुत ही सरल उदाहरण दिया गया है:

यहां गलती "भूल" नहीं है, लेकिन "इसे ठीक नहीं करना" है। यदि आपके पास अप्रत्याशित क्रम में चीजें हो रही हैं, तो आपको एक समस्या है। आपको इसके चारों ओर काम करने की कोशिश करने के बजाय इसे हल करना चाहिए (आमतौर पर किसी काम पर ताला लगाना) एक काम है।

आपको अभिनेता मॉडल / संदेश को कुछ हद तक अनुकूलित करने और चिंता को अलग करने की कोशिश करनी चाहिए। Fooकुछ प्रकार के HTTP संचार को संभालने के लिए स्पष्ट रूप से भूमिका है। यदि आप समानांतर में ऐसा करने के लिए अपने सिस्टम को डिजाइन करना चाहते हैं, तो यह ऊपर की परत है जो ऑब्जेक्ट जीवनचक्र को संभालना चाहिए और तदनुसार तुल्यकालन का उपयोग करना चाहिए।

एक ही परस्पर डेटा पर कई थ्रेड संचालित करने की कोशिश करना कठिन है। लेकिन यह भी शायद ही कभी आवश्यक है। सभी सामान्य मामले जो इसकी मांग करते हैं, पहले से ही अधिक प्रबंधनीय अवधारणाओं में सारगर्भित हैं और किसी भी प्रमुख अनिवार्य भाषा के लिए कई बार लागू हुए हैं। आपको बस उनका उपयोग करना है।


2

आपकी समस्याएं बहुत खराब हैं, लेकिन C ++ के खराब उपयोग के विशिष्ट हैं। कोड की समीक्षा इनमें से कुछ समस्याओं को ठीक कर देगी। 30 मिनट, नेत्रगोलक का एक सेट 90% परिणामों का संकेत देता है। (इसके लिए प्रशस्ति पत्र googleable है)

# 1 समस्या आपको यह सुनिश्चित करने की आवश्यकता है कि आपके लॉकिंग गतिरोध को रोकने के लिए सख्त लॉक पदानुक्रम है।

यदि आप एक आवरण और मैक्रो के साथ ऑटोलॉक को प्रतिस्थापित करते हैं तो आप ऐसा कर सकते हैं।

अपने रैपर के पीछे बने तालों का स्थिर वैश्विक मानचित्र रखें। आप ऑटोलॉक रैपर कंस्ट्रक्टर में फ़ाइनलनेम और लाइन नंबर की जानकारी डालने के लिए मैक्रो का उपयोग करते हैं।

आपको स्थैतिक वर्चस्व ग्राफ की भी आवश्यकता होगी।

अब लॉक के अंदर आपको डोमिनेटर ग्राफ को अपडेट करना होगा, और अगर आपको ऑर्डरिंग चेंज मिलता है तो आप एरर और एबॉर्ट का दावा करते हैं।

व्यापक परीक्षण के बाद आप अव्यक्त गतिरोध के अधिकांश से छुटकारा पा सकते हैं।

कोड को छात्र के लिए एक अभ्यास के रूप में छोड़ दिया जाता है।

समस्या # 2 तब चली जाएगी (ज्यादातर)

आपका अभिलेखीय समाधान काम करने वाला है। मैंने इसे पहले मिशन और जीवन क्रिटिकल सिस्टम में उपयोग किया है। इस पर मेरा ख्याल है

  • पास होने से पहले अपरिवर्तनीय वस्तुओं को पास करें या उनकी प्रतियां बनाएं।
  • सार्वजनिक चर या गेटर्स के माध्यम से डेटा साझा न करें।

  • बाहरी घटनाएँ एक धागे द्वारा सेवित कतार में बहुपरत प्रेषण के माध्यम से आती हैं। अब आप इवेंट हैंडलिंग के बारे में सॉर्ट कर सकते हैं।

  • डेटा परिवर्तन जो क्रॉस थ्रेड्स थ्रेड-सुरक्षित queue में आते हैं, एक थ्रेड द्वारा नियंत्रित होते हैं। सदस्यता लें। अब आप डेटा प्रवाह के बारे में सॉर्ट कर सकते हैं।

  • यदि आपके डेटा को क्रॉस-टाउन जाने की आवश्यकता है, तो इसे डेटा कतार में प्रकाशित करें। वह इसे कॉपी करेगा और इसे ग्राहकों के पास असिंक्रोनस रूप से पास करेगा। कार्यक्रम में सभी डेटा निर्भरताओं को भी तोड़ता है।

यह बहुत सस्ते पर एक अभिनेता मॉडल है। जियोर्जियो के लिंक मदद करेंगे।

अंत में, शट-डाउन ऑब्जेक्ट्स के साथ आपकी समस्या।

जब आप संदर्भ की गिनती कर रहे हैं, तो आप 50% हल कर चुके हैं। अन्य 50% कॉलबैक की गणना करना है। कॉलबैक धारकों को रेफर करें। शटडाउन कॉल के बाद रिफंड पर शून्य गणना के लिए इंतजार करना पड़ता है। जटिल ऑब्जेक्ट ग्राफ़ को हल नहीं करता है; यह वास्तविक कचरा संग्रह में मिल रहा है। (जो कि अंतिम रूप देने पर (या) जब आप को उस तरह की प्रोग्रामिंग से बाहर निकालने के लिए (या) को बुलाया जाएगा, के बारे में कोई वादा नहीं करने के लिए प्रेरणा इन्स जावा है।)


2

भविष्य के खोजकर्ताओं के लिए: अभिनेता मॉडल के बारे में जवाब को पूरक करने के लिए मैं सीएसपी ( अनुक्रमिक प्रक्रियाओं को संप्रेषित करना ) जोड़ना चाहूंगा, यह प्रक्रिया के बड़े परिवार के लिए एक नोड के साथ है। सीएसपी अभिनेता मॉडल के समान है, लेकिन अलग तरह से विभाजित होता है। आपके पास अभी भी धागे का एक गुच्छा है, लेकिन वे विशिष्ट चैनलों के माध्यम से संवाद करते हैं, विशेष रूप से एक दूसरे के साथ, और दोनों प्रक्रियाओं को क्रमशः होने से पहले भेजने और प्राप्त करने के लिए तैयार होना चाहिए। CSP कोड को सही साबित करने के लिए एक औपचारिक भाषा भी है । मैं अभी भी CSP का भारी उपयोग कर रहा हूं, लेकिन मैं इसे कुछ महीनों से कुछ परियोजनाओं में उपयोग कर रहा हूं, और अब यह बहुत सरल हो गया है।

केंट विश्वविद्यालय एक सी ++ कार्यान्वयन (है https://www.cs.kent.ac.uk/projects/ofa/c++csp/ , पर क्लोन https://github.com/themasterchef/cppcsp2 )।


1

धागे के चारों ओर डिजाइन पैटर्न पर साहित्य या कागजात। म्यूटेक्स और सेमाफोरस के परिचय से परे कुछ। हमें बड़े पैमाने पर समानता की आवश्यकता नहीं है, बस किसी ऑब्जेक्ट मॉडल को डिजाइन करने के तरीके ताकि अन्य धागे से अतुल्यकालिक घटनाओं को सही ढंग से संभाल सकें।

मैं वर्तमान में इसे पढ़ रहा हूं और यह उन सभी समस्याओं की व्याख्या करता है जो आप प्राप्त कर सकते हैं और इनसे कैसे बच सकते हैं, C ++ में (नए थ्रेडिंग लाइब्रेरी का उपयोग करके लेकिन मुझे लगता है कि वैश्विक स्पष्टीकरण आपके मामले के लिए वैध हैं): http: //www.amazon। com / सी कन्करेंसी-क्रिया-प्रैक्टिकल-बहु सूत्रण / डी पी / 1933988770 / रेफरी = sr_1_1? यानी = UTF8 और QID = १३३७९३४५३४ और एसआर = 8-1

विभिन्न घटकों के थ्रेडिंग को आरेखित करने के तरीके, ताकि इसके लिए समाधानों का अध्ययन और विकास करना आसान हो। (यानी, वस्तुओं और वर्गों के बीच चर्चा के लिए एक यूएमएल समकक्ष)

मैं व्यक्तिगत रूप से एक सरलीकृत यूएमएल का उपयोग करता हूं और बस यह मानता हूं कि संदेश अतुल्यकालिक रूप से किए जाते हैं। इसके अलावा, यह "मॉड्यूल" के बीच सच है, लेकिन अंदर के मॉड्यूल मुझे जानना नहीं चाहते हैं।

मल्टीट्रेड कोड वाले मुद्दों पर अपनी विकास टीम को शिक्षित करना।

पुस्तक मदद करेगी, लेकिन मुझे लगता है कि अभ्यास / प्रोटोटाइप और अनुभवी संरक्षक दांव होगा।

तुम क्या करोगे?

मैं पूरी तरह से लोगों को इस परियोजना पर काम की समस्याओं को समझने से बचने से बचना होगा। लेकिन मुझे लगता है कि आप ऐसा नहीं कर सकते हैं, इसलिए आपके विशिष्ट मामले में, यह सुनिश्चित करने के अलावा कि टीम अधिक शिक्षित हो जाए, मुझे पता नहीं है।


पुस्तक सुझाव के लिए धन्यवाद। मैं संभवतः इसे उठाऊंगा।
koncurrency

थ्रेडिंग वास्तव में कठिन है। प्रत्येक प्रोग्रामर चुनौती तक नहीं है। व्यापार की दुनिया में, हर बार जब मैंने थ्रेड्स का उपयोग किया, तो वे इस तरह से ताले से घिरे हुए थे कि एक ही समय में दो धागे नहीं चल सकते थे। ऐसे नियम हैं जिन्हें आप आसानी से अपना सकते हैं, लेकिन यह अभी भी कठिन है।
ग्लेनपेटर्सन

@GlenPeterson सहमत हो गए, अब मेरे पास अधिक अनुभव है (इस उत्तर के बाद से) मुझे लगता है कि हमें इसे प्रबंधित करने और साझा करने के डेटा को हतोत्साहित करने के लिए बेहतर अमूर्तता की आवश्यकता है। सौभाग्य से, भाषा डिजाइनर इस पर कड़ी मेहनत करते हैं।
Kलेम

मैं वास्तव में स्काला से प्रभावित हुआ हूं, विशेष रूप से जावा के लिए न्यूनतम प्रोग्रामिंग प्रभाव, अपरिवर्तनीयता के कार्यात्मक प्रोग्रामिंग लाभ लाने के लिए, जो सी ++ का प्रत्यक्ष वंशज है। यह जावा वर्चुअल मशीन पर चलता है, इसलिए हो सकता है कि आपको प्रदर्शन की आवश्यकता न हो। जोशुआ बलोच की पुस्तक "इफेक्टिव जावा" सभी म्यूटेबिलिटी को कम करने, एयरटाइट इंटरफेस बनाने और थ्रेड सेफ्टी के बारे में है। भले ही यह जावा आधारित है, मुझे यकीन है कि आप इसे C ++ में 80-90% लागू कर सकते हैं। आपकी कोड समीक्षाओं में परस्परता और साझा स्थिति (या साझा स्थिति का परिवर्तनशीलता) पर सवाल उठाना आपके लिए एक अच्छा पहला कदम हो सकता है।
ग्लेनपेटर्सन

1

आप पहले से ही समस्या को स्वीकार कर रहे हैं और सक्रिय रूप से समाधान की तलाश कर रहे हैं। यहाँ मैं क्या करूँगा:

  • बैठ जाओ और अपने आवेदन के लिए एक सूत्रण मॉडल तैयार करें। यह एक दस्तावेज है जो प्रश्नों का उत्तर देता है जैसे: आपके पास किस प्रकार के धागे हैं? किन चीजों को किस धागे में करना चाहिए? आपको किस प्रकार के सिंक्रोनाइज़ेशन पैटर्न का उपयोग करना चाहिए? दूसरे शब्दों में, बहुस्तरीय समस्याओं से जूझते समय "सगाई के नियमों" का वर्णन करना चाहिए।
  • त्रुटियों के लिए अपने कोडबेस की जांच करने के लिए थ्रेड विश्लेषण टूल का उपयोग करें। Valgrind में Helgrind नाम से एक थ्रेड चेकर है, जो साझा किए गए राज्य की चीजों को स्पॉट करने में अच्छा है, जिसे उचित सिंक्रनाइज़ेशन के बिना जोड़-तोड़ किया जा रहा है। वहाँ निश्चित रूप से अन्य अच्छे उपकरण हैं, उनके लिए देखो।
  • C ++ से दूर जाने पर विचार करें। C ++ समवर्ती कार्यक्रमों को लिखने के लिए एक बुरा सपना है। मेरी व्यक्तिगत पसंद एर्लैंग होगी , लेकिन यह स्वाद का मामला है।

8
आखिरी बिट के लिए निश्चित रूप से -1। ऐसा प्रतीत होता है कि ओपी कोड सबसे आदिम उपकरणों का उपयोग कर रहा है न कि वास्तविक सी ++ टूल्स का।
डेडएमजी

2
मैं सहमत नहीं हूँ। यदि आप उचित C ++ मेकेनिज्म और टूल्स का उपयोग करते हैं तो भी C ++ में कंसीडर एक बुरा सपना है। और कृपया ध्यान दें कि मैंने शब्द " विचार " को चुना । मैं पूरी तरह से समझता हूं कि यह यथार्थवादी विकल्प नहीं हो सकता है, लेकिन विकल्पों पर विचार किए बिना सी ++ के साथ रहना सिर्फ सादा मूर्खतापूर्ण है।
जेस्पर

4
@ जेस्पर - सॉरी, लेकिन नहीं। यदि आप इसे निम्न स्तर पर जाकर बनाते हैं, तो C ++ में कंसीडर केवल एक बुरा सपना है। उचित थ्रेडिंग अमूर्त का उपयोग करें और यह किसी भी अन्य भाषा या रनटाइम से बदतर नहीं है। और उचित अनुप्रयोग संरचना के साथ, यह वास्तव में काफी आसान है जितना मैंने कभी देखा है।
माइकल कोहेन

2
जहां मैं काम करता हूं मेरा मानना ​​है कि हमारे पास एक उचित एप्लिकेशन संरचना है, सही थ्रेडिंग सार का उपयोग करें, और इसी तरह। इसके बावजूद, हमने पिछले कुछ वर्षों में बगैर डिबगिंग कीड़े के कई घंटे बिताए हैं जो केवल संगामिति के लिए डिज़ाइन की गई भाषाओं में दिखाई नहीं देंगे। लेकिन मुझे लगता है कि हमें इस पर असहमत होने के लिए सहमत होना पड़ेगा।
जेस्पर

1
@ जेस्पर: मैं आपसे सहमत हूँ। एरलैंग मॉडल (जिसके लिए स्काला / जावा, रूबी के लिए कार्यान्वयन मौजूद हैं, और जहां तक ​​मुझे पता है, सी ++ के लिए भी) सीधे थ्रेड्स के साथ कोडिंग की तुलना में अधिक मजबूत है।
जियोर्जियो

1

अपने उदाहरण को देखते हुए: जैसे ही फू :: शटडाउन निष्पादित होना शुरू होता है, उसे अब चलाने के लिए OnHttpRequestComplete को कॉल करना संभव नहीं होना चाहिए। इसका किसी भी क्रियान्वयन से कोई लेना-देना नहीं है, यह सिर्फ काम नहीं कर सकता है।

आप यह भी तर्क दे सकते हैं कि फू :: शटडाउन को कॉल करने योग्य नहीं होना चाहिए, जबकि OnHttpRequestComplete पर कॉल चल रही है (निश्चित रूप से सच है) और शायद नहीं, अगर OnHttpRequestComplete पर कॉल अभी भी बकाया है।

सही होने के लिए पहली चीज लॉकिंग आदि नहीं है, लेकिन क्या अनुमति है या नहीं, का तर्क। एक साधारण मॉडल यह होगा कि आपकी कक्षा में शून्य या अधिक अपूर्ण अनुरोध हो सकते हैं, शून्य या अधिक पूर्णताएं जिन्हें अभी तक नहीं बुलाया गया है, शून्य या अधिक पूर्णताएं जो चल रही हैं, और यह कि आपकी वस्तु बंद करना चाहती है या नहीं।

फू :: शटडाउन से अपेक्षाओं को पूरा करने की अपेक्षा की जाएगी, उस बिंदु पर अपूर्ण अनुरोधों को चलाने के लिए जहां वे संभव हो तो बंद किया जा सकता है, किसी भी अधिक पूर्णता को शुरू करने की अनुमति नहीं देने के लिए, और अधिक अनुरोधों को शुरू करने की अनुमति नहीं देने के लिए।

आप क्या करने की जरूरत: कह रही है अपने कार्यों के लिए चश्मा जोड़े वास्तव में वे क्या करेंगे। (उदाहरण के लिए, HTTP अनुरोध शुरू करना शटडाउन हास कहे जाने के बाद विफल हो सकता है)। और फिर अपने कार्यों को लिखें ताकि वे ऐनक से मिलें।

साझा चर के संशोधन को नियंत्रित करने के लिए ताले का उपयोग केवल सबसे कम समय में संभव राशि के लिए किया जाता है। तो आपके पास एक चर "PerformShutDown" हो सकता है जो एक लॉक द्वारा संरक्षित है।


0

तुम क्या करोगे?

ईमानदार रहना; मैं जल्दी से भाग जाता।

समसामयिक मुद्दे NASTY हैं । कुछ महीनों तक पूरी तरह से काम कर सकते हैं और फिर (कई चीजों के विशिष्ट समय के कारण) अचानक ग्राहक के चेहरे पर उड़ जाते हैं, यह पता लगाने का कोई तरीका नहीं है कि क्या हुआ, कभी भी एक अच्छी (प्रतिलिपि प्रस्तुत करने योग्य) बग रिपोर्ट देखने की कोई उम्मीद नहीं है और कोई रास्ता नहीं है यह भी सुनिश्चित करें कि यह एक हार्डवेयर गड़बड़ नहीं था जिसका सॉफ्टवेयर से कोई लेना-देना नहीं है।

अवशिष्ट समस्याओं से बचने के लिए डिज़ाइन चरण के दौरान शुरू करने की आवश्यकता होती है, ठीक उसी तरह से शुरू करते हैं जब आप इसे करने जा रहे हैं ("वैश्विक लॉक ऑर्डर", अभिनेता मॉडल, ...)। यह कुछ ऐसा नहीं है जिसे आप इस उम्मीद में पागल आतंक में ठीक करने की कोशिश करते हैं कि आगामी रिलीज के बाद सब कुछ स्वयं-विनाश नहीं होगा।

ध्यान दें कि मैं यहां मजाक नहीं कर रहा हूं। आपके स्वयं के शब्द ("इसमें से अधिकांश अन्य डेवलपर्स से उत्पन्न हुए हैं, जिन्होंने टीम को छोड़ दिया है। टीम के वर्तमान डेवलपर्स बहुत स्मार्ट हैं, लेकिन ज्यादातर अनुभव के मामले में जूनियर हैं। ") संकेत देते हैं कि अनुभव के सभी लोग पहले ही कर चुके हैं जो मैंने किया है। सुझाव दे रहा हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.