2010-03-19 11 views
17

पर परमाणु स्वैप मैं यह सत्यापित करना चाहता हूं कि मेरी समझ सही है। इस तरह की चीज मुश्किल है इसलिए मुझे यकीन है कि मुझे कुछ याद आ रहा है। मेरे पास एक प्रोग्राम है जिसमें रीयल-टाइम थ्रेड और गैर-रीयल-टाइम थ्रेड शामिल है। मैं चाहता हूं कि गैर-आरटी थ्रेड आरटी थ्रेड द्वारा उपयोग की जाने वाली मेमोरी में पॉइंटर को स्वैप करने में सक्षम हो।जीएनयू सी ++

// global 
Data *rt_data; 

Data *swap_data(Data *new_data) 
{ 
#ifdef __GNUC__ 
    // Atomic pointer swap. 
    Data *old_d = __sync_lock_test_and_set(&rt_data, new_data); 
#else 
    // Non-atomic, cross your fingers.           
    Data *old_d = rt_data; 
    rt_data = new_data; 
#endif 
    return old_d; 
} 

इस कार्यक्रम (प्रारंभिक सेटअप के अलावा अन्य) जहां rt_data संशोधित किया गया है में केवल जगह है:

डॉक्स से, मैं समझता हूँ कि इस के साथ g++ में पूरा किया जा सकता है। जब rt_data रीयल-टाइम संदर्भ में उपयोग किया जाता है, तो इसे स्थानीय सूचक में कॉपी किया जाता है। old_d के लिए, बाद में जब यह सुनिश्चित हो जाता है कि पुरानी मेमोरी का उपयोग नहीं किया जाता है, तो इसे गैर-आरटी धागे में मुक्त किया जाएगा। क्या ये सही है? क्या मुझे कहीं भी volatile चाहिए? क्या मुझे अन्य सिंक्रनाइज़ेशन प्राइमेटिव्स कॉल करना चाहिए?

तरह से मैं सी ++ में यह कर रहा हूं करके, हालांकि मैं में दिलचस्पी रखता हूँ कि क्या जवाब सी

समय से आगे

धन्यवाद के लिए अलग है।

उत्तर

24

आम तौर पर volatile का उपयोग न करें C/C++ में समवर्ती कोड लिखते समय।volatile के अर्थशास्त्र जो आप चाहते हैं उसके करीब हैं, लेकिन यह अंतहीन अस्थिर not enough है। दुर्भाग्य से Java/C# volatile != C/C++ volatile। हर्ब सटर में एक महान article भ्रमित गड़बड़ी समझाता है।

जो आप वास्तव में चाहते हैं वह एक स्मृति बाड़ है। __sync_lock_test_and_set आपके लिए बाड़ लगाने प्रदान करता है।

जब आप rt_data पॉइंटर को अपनी स्थानीय प्रतिलिपि में कॉपी (लोड) करते हैं तो आपको मेमोरी बाड़ की भी आवश्यकता होगी।

लॉक फ्री प्रोग्रामिंग मुश्किल है। आप जीसीसी C++ 0x एक्सटेंशन का उपयोग करने के लिए तैयार कर रहे हैं, यह थोड़ा आसान है:

#include <cstdatomic> 

std::atomic<Data*> rt_data; 

Data* swap_data(Data* new_data) 
{ 
    Data* old_data = rt_data.exchange(new_data); 
    assert(old_data != new_data); 
    return old_data; 
} 

void use_data() 
{ 
    Data* local = rt_data.load(); 
    /* ... */ 
} 
+0

धन्यवाद! मैं std :: परमाणु का उपयोग करने के आपके सुझाव का पालन कर सकता हूं, यह उत्कृष्ट है। (मैं अभी तक नवीनतम सी ++ 0x सामान से परिचित नहीं हूं।) जिज्ञासा से बाहर, अगर मैं __sync_lock_test_and_set का उपयोग करता हूं, तो पढ़ने के दौरान उपयोग करने के लिए सही बाड़ क्या है? (यानी, एक स्थानीय प्रतिलिपि बनाने के लिए) – Steve

3

अद्यतन: इस जवाब के रूप में मैं इस तथ्य है कि volatile गारंटी देता है कि volatile चर तक पहुँचता पुनर्क्रमित नहीं कर रहे हैं याद आ रही है, सही नहीं है, लेकिन अन्य गैर volatile पहुंच और जोड़तोड़ के संबंध में इस तरह के कोई गारंटी प्रदान करता है। एक स्मृति बाड़ ऐसी गारंटी प्रदान करती है, और इस एप्लिकेशन के लिए आवश्यक है। मेरा मूल उत्तर नीचे है, लेकिन इस पर कार्रवाई न करें। मेरी समझ में छेद में एक अच्छी व्याख्या के लिए this answer देखें जिससे निम्नलिखित गलत प्रतिक्रिया हुई।

मूल जवाब:

हाँ, आप volatile अपने rt_data घोषणा पर की जरूरत है; किसी भी समय एक चर को उस धागे के नियंत्रण के प्रवाह के बाहर संशोधित किया जा सकता है, इसे volatile घोषित किया जाना चाहिए। जबकि आप volatile के बिना दूर जाने में सक्षम हो सकते हैं, क्योंकि आप स्थानीय सूचक में प्रतिलिपि बना रहे हैं, volatile कम से कम दस्तावेज़ीकरण में सहायता करता है और कुछ संकलक अनुकूलन को भी रोकता है जो समस्याएं पैदा कर सकता है। निम्न उदाहरण, DDJ से अपनाया पर विचार करें:

volatile int a; 
int b; 
a = 1; 
b = a; 

तो यह संभव है a अपने मूल्य a=1 और b=a के बीच बदलवाने के लिए के लिए है, तो avolatile घोषित किया जाना चाहिए (जब तक, ज़ाहिर है, एक बताए बाहर के- दिनांक मूल्य b स्वीकार्य है)। मल्टीथ्रेडिंग, विशेष रूप से परमाणु प्राइमेटिव के साथ, ऐसी स्थिति का गठन करती है। स्थिति सिग्नल हैंडलर द्वारा संशोधित चर के साथ और अजीब स्मृति स्थानों (जैसे हार्डवेयर I/O रजिस्टरों) में मैप किए गए चर के साथ भी ट्रिगर की जाती है। this question भी देखें।

अन्यथा, यह मेरे लिए ठीक लग रहा है।

सी में, मैं शायद इसके लिए GLib द्वारा प्रदत्त परमाणु प्राइमेटिव का उपयोग करूंगा। वे परमाणु संचालन उपलब्ध नहीं होने पर उपलब्ध एक परमाणु संचालन का उपयोग करेंगे और धीमे-लेकिन-सही म्यूटेक्स-आधारित कार्यान्वयन पर वापस आ जाएंगे। बूस्ट सी ++ के लिए कुछ समान प्रदान कर सकता है।

+5

वाष्पशील संगामिति के साथ कोई संबंध नहीं है, वे पूरी तरह से ओर्थोगोनल हैं। वे दोनों लोड/स्टोर और रीडरिंग को मजबूर करने के साथ सौदा करते हैं, लेकिन अस्थिर द्वारा प्रदान की गई गारंटी समवर्ती समस्याओं का समाधान नहीं करती है। –

+0

@ कैस्पिन हां, अस्थिरता समवर्ती मुद्दों के लिए ऑर्थोगोनल है, और अकेले अस्थिर पर्याप्त नहीं है। हालांकि, यह मेरी समझ है कि अस्थिर प्रोग्रामिंग में अस्थिर उपयोगी है यह सुनिश्चित करने के लिए कि धागे एक-दूसरे के परिवर्तन देखें। किसी अन्य थ्रेड द्वारा परिवर्तनीय परिवर्तन के बीच बहुत अंतर नहीं होता है और इसे हार्डवेयर बाधा द्वारा बदला जा रहा है - दोनों लोड/स्टोर रीडरिंग के लिए जरूरी धारणाओं का उल्लंघन करते हैं, और अस्थिर संकलक को बताता है कि उन धारणाओं को जरूरी नहीं है। –

+0

ऑर्थोगोनल का मतलब है कि अस्थिर हल की समस्याएं समवर्ती प्रोग्रामिंग की समस्या नहीं होती हैं। विशेष रूप से, अस्थिर की ऑर्डरिंग गारंटी केवल वर्तमान धागे पर लागू होती है और केवल अन्य वाष्पशीलताओं के संबंध में होती है। कृपया मेरे उत्तर में दिए गए लिंक पढ़ें क्योंकि अस्थिरता का पूरा विवरण एक टिप्पणी में फिट होना बहुत जटिल है। या बेहतर अभी तक stackoverflow पूछें "सी/सी ++ समवर्ती प्रोग्रामिंग के लिए अस्थिर उपयोगी क्यों नहीं है?" और मैं गहराई से जवाब प्रदान करूंगा। –

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