2010-10-16 16 views
5

संपादित और जोहान्स के मूल्यवान जवाब के बाद मेरे सवाल का परिष्कृतक्या अस्थिरता आवश्यक है?

bool b = true; 
volatile bool vb = true;  
void f1() { } 
void f2() { b = false; } 

void(* volatile pf)() = &f1; //a volatile pointer to function 

int main() 
{ 
    //different threads start here, some of which may change pf 
    while(b && vb) 
    { 
     pf(); 
    } 
} 

तो चलिए थोड़ी देर के लिए तुल्यकालन भूल करते हैं। सवाल यह है कि बी को अस्थिर घोषित किया जाना है या नहीं। मैंने अस्थिर अर्थशास्त्र की औपचारिक परिभाषा को मानक और क्रमबद्ध पढ़ा है (मैं उन्हें लगभग समझता हूं, शब्द लगभग कुंजी है)। लेकिन चलो थोड़ा अनौपचारिक हो। यदि संकलक देखता है कि लूप में बी को बदलने के लिए कोई रास्ता नहीं है, तब तक जब तक बी अस्थिर न हो, तो यह इसे अनुकूलित कर सकता है और मान लेता है कि यह while(vb) के बराबर है। सवाल यह है कि, इस मामले में पीएफ स्वयं अस्थिर है, तो क्या संकलक को यह मानने की अनुमति है कि बी लूप में नहीं बदलेगा, भले ही बी अस्थिर न हो?

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

मुझे आशा है कि मेरा प्रश्न स्पष्ट है। TIA

संपादन एक बार फिर:
इस बारे में क्या?

bool b = true; 
volatile bool vb = true; 
void f1() {} 
void f2() {b = false;} 
void (*pf)() = &f1; 

#include <iosrteam> 
int main() 
{ 
    //threads here 

    while(b && vb) 
    { 
     int x; 
     std::cin >> x; 
     if(x == 0) 
     pf = &f1; 
     else 
     pf = &f2;  
     pf(); 
    } 
} 

क्या दो कार्यक्रमों के बीच एक प्रमुख अंतर है। यदि हां, तो क्या अंतर है?

+0

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

+0

यह वैध सी है यदि आप # – ybungalobill

+0

शामिल करें तो कृपया पहला कोड अपना प्रश्न उठाओ, और फिर पूछें। किसी के जवाब को लगातार बदलना कोई मजेदार नहीं है। इसके अलावा, धागे को बदलने की अनुमति क्या है (उचित सिंक्रनाइज़ेशन मानते हुए)? क्या कुछ हिस्सों के आसपास म्यूटेक्स हैं? (यानी "असाइन-पीएफ + कॉल" भाग के आसपास?) –

उत्तर

3

सवाल यह है कि, इस मामले में पीएफ स्वयं अस्थिर है, तो क्या संकलक को यह मानने की अनुमति है कि बी लूप में नहीं बदलेगा, भले ही बी अस्थिर न हो?

यह है क्योंकि आप का कहना है कि pf अन्य थ्रेड द्वारा बदला जा सकता है, और यह परोक्ष रूप से बदलता है bpf अगर जबकि पाश से तो कहा जाता है नहीं कर सकते हैं,। इसलिए, सैद्धांतिक रूप से b पढ़ने के लिए सैद्धांतिक रूप से आवश्यक नहीं है, इसे अभ्यास में यह निर्धारित करने के लिए पढ़ना चाहिए कि इसे शॉर्ट सर्किट होना चाहिए (जब bfalse बन जाता है तो इसे vb किसी अन्य समय नहीं पढ़ना चाहिए)। इसलिए संकलक यह से छुटकारा पाने के लिए और देखने के f1 एक खाली शरीर और f2 सेट गलत पर b है कि कर सकते हैं


दूसरे भाग

इस मामले pf में करने के लिए उत्तर नहीं अस्थिर अब, है। के रूप में

int main() 
{ 
    // threads here (which you say can only change "vb") 

    while(vb) 
    { 
     int x; 
     std::cin >> x; 
     if(x != 0) 
     break;  
    } 
} 

बड़े संशोधन के जवाब इस प्रकार यह main का अनुकूलन कर सकता है

एक शर्त संकलक पाश अनुकूलन करने के लिए अनुमति दी जा के लिए दूर है कि पाश का उपयोग या किसी अस्थिर संशोधित नहीं करता है ऑब्जेक्ट (देखें [stmt.iter] p5 n3126 में)। आप इसे यहां करते हैं, इसलिए यह लूप को अनुकूलित नहीं कर सकता है। सी ++ 03 में एक कंपाइलर को उस लूप के गैर-अस्थिर संस्करण को अनुकूलित करने की अनुमति नहीं थी (लेकिन संकलक इसे वैसे भी करते थे)।

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

+0

@ जोहान्स: ठीक है, यह लूप को ठीक से अनुकूलित नहीं कर सकता है, लेकिन क्या इसे दूर करने के लिए ऑप्टिमाइज़ करने की अनुमति है और लूप स्थिति के रूप में अपना मान नहीं पढ़ा है? अर्थात। इसे अनंत लूप में परिवर्तित करें? अनंत लूप कहने से बचने के लिए, मान लें कि यह समय था (बी && some_other_volatile_bool)। क्या संकलक इसे इसे बदलने के लिए अनुमति देता है (some_other_volatile_bool)? –

+0

@ आर्मन निश्चित रूप से, यदि 'बी' कभी नहीं बदला जाता है तो सी ++ 03 पूरी तरह से अनुमति देता है। इसे अस्थिर होने की आवश्यकता नहीं है क्योंकि इसे इसे अनुकूलित करने की अनुमति नहीं है। –

+0

@ जोहान्स: मेरे प्रश्न को संपादित किया। मैं यह भी नहीं कह सकता कि मैं जवाब से पूरी तरह से संतुष्ट हूं। आप देखते हैं, आपका उत्तर यह भी दर्शाता है कि यदि किसी लूप में पॉइंटर-टू-फ़ंक्शन के माध्यम से कॉल होता है जो उपयोगकर्ता इनपुट के अनुसार लूप के अंदर सेट होता है तो कंपाइलर मान सकता है कि बी नहीं बदलता है, जिसे मैं विश्वास नहीं करना चाहता । क्या मैं? –

0

अस्थिर केवल आपको दर्द देता है अगर आपको लगता है कि आप एक अनुकूलन से लाभान्वित हो सकते हैं जो नहीं किया जा सकता है या यदि यह सच है जो सत्य नहीं है।

आपके मामले में, आपने कहा कि इन चरों को अन्य धागे द्वारा बदला जा सकता है। कोड पढ़ना, यह मेरी धारणा है जब मैं अस्थिर दिखता हूं, इसलिए एक रखरखाव के परिप्रेक्ष्य से, यह अच्छा है - यह मुझे अतिरिक्त जानकारी दे रहा है (जो सच है)।

मुझे नहीं पता कि अनुकूलन बचाने के लायक हैं या नहीं, क्योंकि आपने कहा है कि यह वास्तविक कोड नहीं है, लेकिन यदि वे नहीं हैं तो अस्थिरता का उपयोग करने के कोई कारण नहीं हैं।

जब आप गलत व्यवहार में परिणाम प्राप्त करते हैं तो अस्थिरता का उपयोग नहीं करते हैं, क्योंकि अनुकूलन कोड के अर्थ को बदल रहे हैं।

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

2

इस तरह के मामले में वर्तमान सी ++ मानक में volatile पर सटीक आवश्यकताएं हैं, जैसा कि मैं इसे समझता हूं, मानक द्वारा पूरी तरह से परिभाषित नहीं है, क्योंकि मानक वास्तव में बहु-थ्रेडिंग से निपटता नहीं है। यह मूल रूप से एक संकलक संकेत है। तो, इसके बजाय, मैं एक ठेठ संकलक में क्या होता है पता चलेगा।

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

अपना पहला वास्तविक मामले के लिए है कि विस्तार, और संकलक पूरे कार्यक्रम अनुकूलन बनाने के लिए अनुमति देता है, क्योंकि pf अस्थिर संकलक अभी भी पता नहीं क्या यह (यह भी कल्पना नहीं कर सकते यह या तो f1 है पर इंगित किया जा रहा है है या f2!), और इसी प्रकार फ़ंक्शन-पॉइंटर कॉल में अनमोडिफाइड किए जाने के बारे में कोई धारणा नहीं हो सकती है - और b पर अभी भी अप्रासंगिक है।

आपका दूसरा मामला वास्तव में सरल है - इसमें vb एक लाल हेरिंग है। यदि आप इसे खत्म करते हैं, तो आप देख सकते हैं कि पूरी तरह से सिंगल-थ्रेडेड सेमेन्टिक्स में भी, फ़ंक्शन-पॉइंटर कॉल b संशोधित कर सकता है। आप अपरिभाषित व्यवहार के साथ कुछ भी नहीं कर रहे हैं, और इसलिए प्रोग्राम volatile के बिना सही ढंग से काम करना चाहिए - याद रखें कि, यदि आप बाहरी थ्रेड tweaks के साथ किसी स्थिति पर विचार नहीं कर रहे हैं, volatile एक नो-ऑप है। इसलिए, चित्र में vb के बिना, आपको संभवतः volatile की आवश्यकता नहीं हो सकती है, और यह स्पष्ट है कि vb जोड़ना कुछ भी नहीं बदलता है।

इस प्रकार, संक्षेप में: आपको किसी भी मामले में volatile की आवश्यकता नहीं है।अंतर, जैसा कि एक है, यह है कि पहले मामले में यदि fp अस्थिर नहीं थे, तो पर्याप्त रूप से उन्नत कंपाइलर संभवतः b दूर अनुकूलित कर सकता है, जबकि यह दूसरे मामले में प्रोग्राम में कहीं भी अस्थिर नहीं हो सकता है। प्रैक्टिस में, मुझे उम्मीद नहीं है कि किसी भी कंपाइलर्स वास्तव में उस अनुकूलन को बनाएगा।

+0

मेरे दूसरे उदाहरण में, संकलक आमतौर पर समझेंगे कि पीएफ या तो एफ 1 या एफ 2 है, उन दोनों कार्यों का विश्लेषण करें और देखें कि बी बदल सकता है, या पॉइंटर-टू-फ़ंक्शन का केवल आमंत्रण इसके लिए से बचने के लिए पर्याप्त है अनुकूलन एक वैश्विक चर से पढ़ता है? –

+0

और, आकस्मिक रूप से, सी ++ 0x बहु-थ्रेडिंग के साथ सौदा करता है ... बहुत –

+0

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

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