2017-10-27 29 views
6

के साथ लूप पर जीसीसी अनुकूलन प्रभाव मैं एक सी ++ कोड अनुकूलित कर रहा था जिसमें मुझे ऐसी स्थिति का सामना करना पड़ा जिसे निम्नानुसार सरल बनाया जा सकता है।स्पष्ट रूप से निरंतर परिवर्तनीय

इस कोड पर विचार करें:

#include <iostream> 
#include <thread> 

using namespace std; 

bool hit = false; 

void F() 
{ 
    this_thread::sleep_for(chrono::seconds(1)); 
    hit = true; 
} 

int main() 
{ 
    thread t(F); 

    while (!hit) 
     ; 

    cout << "finished" << endl; 
    t.join(); 
    return 0; 
} 

यह मूल रूप से एक धागा जो एक दूसरे के बाद true को hit का मूल्य बदल जाएगा शुरू होता है। साथ ही कोड एक खाली पाश में प्रवेश करता है जो hit का मान true बन जाएगा जब तक जारी रहेगा। मैंने इसे gcc-5.4-g ध्वज का उपयोग करके संकलित किया और सब कुछ ठीक था। कोड finished आउटपुट करेगा और समाप्त होगा। लेकिन फिर मैंने इसे -O2 ध्वज के साथ संकलित किया और इस बार कोड लूप में असीमित रूप से फंस गया।

disassembly को देखते हुए, संकलक निम्नलिखित है, जो अनंत लूप की जड़ है उत्पन्न किया था:

JMP 0x6ba6f3! 0x00000000006ba6f3

ठीक है, तो स्पष्ट रूप से, संकलक निष्कर्ष निकाला गया है कि hit के मूल्य false है और यह पाश में परिवर्तन नहीं होगा तो क्यों यह न समझें कि यह एक अनंत लूप है कि एक और धागा अपने मूल्य बदल सकते हैं पर विचार किए बिना ! और यह अनुकूलन मोड उच्च स्तर (-O2) में जोड़ा जाता है। चूंकि मैं बिल्कुल अनुकूलन ध्वज विशेषज्ञ नहीं हूं, क्या कोई मुझे बता सकता है कि इनमें से कौन सा परिणाम इस परिणाम के लिए ज़िम्मेदार है, इसलिए मैं इसे बंद कर सकता हूं? और इसे बंद करने से कोड के अन्य टुकड़ों के लिए कोई बड़ी प्रदर्शन लागत होगी? मेरा मतलब है, कोड का यह पैटर्न दुर्लभ है?

+1

'std :: atomic ' का उपयोग करें। – Jarod42

+2

क्या होता है यदि आप 'हिट' को अस्थिर घोषित करते हैं? – Milack27

+0

@ मिलैक 27 हां यह समस्या हल करता है! मैन, सी ++ में कई चीजें हैं जिन्हें मैं अभी भी नहीं जानता! – Sinapse

उत्तर

6

इस कोड में अनिश्चित व्यवहार है। आप hit को एक थ्रेड से संशोधित कर रहे हैं और सिंक्रनाइज़ेशन के बिना इसे दूसरे रूप में पढ़ रहे हैं।

hit से false को अनुकूलित करना अपरिभाषित व्यवहार का एक वैध परिणाम है। आप इसे hitstd::atomic<bool> बनाकर हल कर सकते हैं। यह अच्छी तरह से परिभाषित करता है, और अनुकूलन ब्लॉक करता है।

+0

हां यह भी समस्या को हल करेगा (मुझे लगता है कि अस्थिर मेरे मामले के लिए इसे और अधिक कुशलतापूर्वक करेगा) लेकिन ओएमजी !! जब आप चरम पर परमाणु के रूप में परिभाषित करते हैं तो संकलक इसे कैसे जानता है ?! मेरा मतलब अस्थिर समझ में आता है क्योंकि आप क्वालीफायर जोड़ रहे हैं लेकिन std :: परमाणु के मामले में, कैसे संकलक कम करेगा कि यह किसी अन्य धागे में बदल सकता है ?? – Sinapse

+0

क्या सोचो! 'Std :: atomic ' कक्षा के अंदर अस्थिर सदस्य हैं। :) g ++ से "परमाणु" फ़ाइल खोलने का प्रयास करें फ़ोल्डर में, आप उन्हें वहां देख सकते हैं। – Milack27

+0

अच्छा, वह योग्य था! – Sinapse

2

यदि आप एक ही समय में कई धागे से hit पढ़ना/लिखना चाहते हैं तो आपको किसी प्रकार की सिंक्रनाइज़ेशन की आवश्यकता है अन्यथा आप दौड़ की स्थिति पेश करेंगे। आप या तो hit एक std::atomic<bool> बनाने या एक mutex जब hit मूल्य तक पहुँचने बंद कर दिया जाना चाहिए जोड़ सकते हैं। यदि आप किसी भी अतिरिक्त झंडे को पेश किए बिना बस thread.join() (और उसके बाद "समाप्त" प्रिंट) छोड़कर थ्रेड के लिए अपनी नौकरी खत्म करने के लिए प्रतीक्षा करना चाहते हैं।

1

hit के रूप में अस्थिर घोषित करके, आप संकलक कि इस परिवर्तनीय किसी भी समय बाहरी कारकों से संशोधित किया जा सकता कह रहे हैं, तो संकलक मान नहीं होगा कि अपने मूल्य अपने main समारोह के साथ नहीं बदलेगा।

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

+0

'अस्थिर '[आवश्यक आदेश प्रदान करने में विफल रहता है] (https://stackoverflow.com/a/4558031/15416)। – MSalters

+0

हां। जैसा कि मैंने कहा, _it हमेशा सिंक्रनाइज़ेशन tools_ का उपयोग करने के लिए सुरक्षित है। 'Volatile' का उपयोग करना इस मामले में ठीक से काम करना चाहिए _। – Milack27

संबंधित मुद्दे