2013-06-03 5 views
5

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

स्थिति: struct के अंदर, Busy नामक एक हस्ताक्षरित चार चर है। (इसे वहां से बाहर ले जाया जा सकता है और अपने आप पर खड़ा हो सकता है)।

यह चर Busy दो समवर्ती धागे द्वारा संशोधित किया गया है, जो शेड्यूलिंग पर बिट सेट करता है और जो निर्धारित समय के पूरा होने पर उन्हें साफ़ करता है।

अभी, समय निर्धारण इस तरह दिखता है:

while(SEC.Busy&(1 << SEC.ReqID)) 
    if(++SEC.ReqID == 5) SEC.ReqID = 0; 
sQuery.cData[2] = SEC.ReqID; 

bitmaks के समाशोधन इस तरह दिखता है, जबकि:

SEC.Busy &= ~(1 << sQuery->cData[2]); 

CDATA [2] मूल रूप से जानकारी के बारे में जो स्लॉट प्रयोग किया जाता है वहन करती है नेटवर्क पर और किसी अन्य थ्रेड में कॉलबैक के माध्यम से वापस आता है।

अब प्रश्न: मैं कैसे सुनिश्चित कर सकता हूं कि SEC.Busy (जो इस परेशानी की स्थिति में एकमात्र चर है) एक म्यूटेक्स का उपयोग किये बिना एक ही समय में इसे बदलने की कोशिश कर रहे दो धागे से अलग नहीं हो जाता है, यदि संभव हो तो महत्वपूर्ण अनुभाग या पसंद के कुछ भी?

मैंने स्थानीय चर में SEC.Busy की सामग्री को असाइन करने का भी प्रयास किया है, फिर उसे बदलें और फिर चर को वापस लिखें, लेकिन दुर्भाग्यवश यह ऑपरेशन परमाणु प्रतीत नहीं होता है।

मैं इस समय बोर्लैंड सी ++ बिल्डर 6 का उपयोग कर रहा हूं, हालांकि एक जीसीसी समाधान भी ठीक होगा।

बहुत बहुत धन्यवाद।

+1

एक भी चार पर बिट्स की स्थापना भयानक लग रहा है * *। समेकन का झुकाव साझा कर रहा है, और यहां आप बिना किसी व्यर्थ साझाकरण के टन को लागू कर रहे हैं। यदि आप स्मृति को छोड़ सकते हैं, तो प्रत्येक ध्वज को किसी शब्द के आकार पर कब्जा कर लें, या फिर एक संपूर्ण कैश लाइन (64 बाइट्स) बेहतर हो। –

+0

@KerrekSB तो आप सुझाव दे रहे हैं कि मैं एक चरित्र के बजाय बुलियन वर्णों की एक सरणी का उपयोग कर रहा हूं, सही? – ATaylor

+0

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

उत्तर

5

सी ++ 03 (न ही सी 99) परमाणुता के बारे में कुछ भी नहीं कहता है। असाइनमेंट अधिकांश प्लेटफॉर्म पर परमाणु (= हर कोई पुराना या नया मान देखता है) है, लेकिन क्योंकि यह सिंक्रनाइज़ नहीं है (= किसी को भी अन्य अपडेट के लिए नया मान देखने के बाद पुराना मान दिखाई दे सकता है), यह बेकार है वैसे भी। कोई अन्य ऑपरेशन जैसे कि वृद्धि, सेट बिट और ऐसा संभवतः परमाणु भी नहीं है।

सी ++ 11 std::atomic template परिभाषित करता है, जो परमाणुता और सिंक्रनाइज़ेशन दोनों को सुनिश्चित करता है, इसलिए आपको इसका उपयोग करने की आवश्यकता है। बूस्ट सबसे सी ++ 03 संकलनकर्ता और जीसीसी has had built-in support since 4.2 के लिए संगत कार्यान्वयन, जो more advanced support needed by C++11 in gcc 4.7

Windows API द्वारा प्रतिस्थापित किया जा रहा है के बाद से बहुत पहले "Interlocked operations" था प्रदान करता है। जीसीसी __sync फ़ंक्शन की शुरूआत से पहले यूनिक्स वैकल्पिक आवश्यक असेंबली (जो कई पुस्तकालय प्रदान की गई)।

+0

मैं अपने माफी भीख माँगती हूँ, लेकिन इसका मतलब यह है, (जो बीसीबी 6 जहाँ तक मुझे पता है कर रहा हूँ ऐसा नहीं कर सकते), मैं अटक कर रहा हूँ जब तक मेरी संकलक सी ++ 11 प्रदर्शन कर सकते हैं? या फिर इसका मतलब यह है कि मैं 'अच्छा' हूं, फिर भी ऑपरेशन परमाणु है, फिर भी यह असेंबलर को देखते समय कई संचालन के रूप में दिखाई देने के बावजूद है? इसके अलावा, यहां तक ​​कि यदि कोई दौड़ की स्थिति है, तो यह मुझे इस मामले में चोट नहीं पहुंचाता है, क्योंकि यदि स्लॉट को 'कब्जा' के रूप में पढ़ा जा रहा है, तो इसे भी अगली बार में इस्तेमाल किया जाएगा। क्या वह काम करेगा? – ATaylor

+0

नहीं, आप अटक नहीं गए हैं। आप बस एक कंपाइलर का उपयोग कर सकते हैं जो थोड़ी अधिक अद्यतित है। बीसीबी 6 2002 से है, जो सी ++ 03 मानक से पहले भी था। अब हमारे पास 2013 है, सी ++ 11 पहले कंपेलरों के फीचर को पूरा कर रहा है, और सी ++ 14 सामुदायिक मसौदा पहले से ही बाहर है। –

+0

@ATaylor: बीसीबी 6 विंडोज-विशिष्ट है। तो बस 'इंटरलॉक *' फ़ंक्शंस का उपयोग करें। –

0

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

unsigned char के एक चर का उपयोग करके लगभग निश्चित रूप से पहले को हटा दिया जाता है, लेकिन इसका अन्य दोनों पर कोई प्रभाव नहीं पड़ता है।

सभी तीन समस्याओं से बचने के लिए, C++ 11 से atomic<unsigned char> या आपके कंपाइलर और ओएस प्रदान करने वाली तकनीकों को सिंक्रनाइज़ करने वाली तकनीक का उपयोग करें।

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