2009-02-27 13 views
17

पर इंट 64 उपयोग है, मैंने एमएस दस्तावेज में पढ़ा है कि 32-बिट इंटेल कंप्यूटर पर 64-बिट मान निर्दिष्ट करने पर परमाणु ऑपरेशन नहीं है; यानी, ऑपरेशन थ्रेड सुरक्षित नहीं है। इसका अर्थ यह है कि यदि दो लोग एक साथ स्थिर Int64 फ़ील्ड को मान निर्दिष्ट करते हैं, तो फ़ील्ड का अंतिम मान भविष्यवाणी नहीं किया जा सकता है।सी # के तहत 32 बिट प्रोसेसर खतरनाक

तीन भाग प्रश्न:

  • यह वास्तव में सच है?
  • क्या यह कुछ असली दुनिया में चिंता करने वाला है?
  • यदि मेरा आवेदन बहु-थ्रेडेड है तो क्या मुझे वास्तव में लॉकिंग कोड के साथ अपने सभी Int64 असाइनमेंट को घेरने की आवश्यकता है?
+3

इंट 64 पर परमाणु संचालन के लिए, आप इंटरलाक्ड क्लास (http://msdn.microsoft.com/en-us/library/system.threading.interlocked.add.aspx) का उपयोग कर सकते हैं। –

उत्तर

18

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

+0

यह सही है, हालांकि यह स्पष्ट नहीं हो सकता है कि क्यों। एक इंट 64 सिस्टम से विरासत में मिला है।ValueType, जिसका अर्थ है कि मूल्य ढेर पर संग्रहीत किया जाता है। चूंकि प्रत्येक थ्रेड को अपना स्वयं का कॉल स्टैक मिलता है, इसलिए प्रत्येक थ्रेड का अपना मान होता है, यहां तक ​​कि एक ही फ़ंक्शन को कॉल करते समय भी। – codekaizen

+0

कक्षा एक्स {int n; }। क्या यह संदर्भ या मूल्य प्रकार है? क्या इसे ढेर या ढेर में रखा जाएगा? –

+0

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

7

MSDN:

इस प्रकार का एक उदाहरण नियत सभी हार्डवेयर पर सुरक्षित थ्रेड नहीं प्लेटफार्मों क्योंकि कि उदाहरण के द्विआधारी प्रतिनिधित्व एक भी परमाणु आपरेशन में आवंटित करने के लिए बहुत बड़ा हो सकता है।

लेकिन यह भी:

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

+2

सच है, कीवर्ड ** साझा चर ** है। –

1

32-बिट x86 प्लेटफॉर्म पर स्मृति का सबसे बड़ा परमाणु आकार का टुकड़ा 32-बिट है।

इसका मतलब है कि यदि 64-बिट आकार वाले चर से कुछ लिखता है या पढ़ता है तो निष्पादन के दौरान पूर्व-खाली होने के लिए पढ़ने/लिखने के लिए यह संभव है।

  • उदाहरण के लिए, आप 64 बिट चर के लिए एक मान असाइन करना शुरू करते हैं।
  • पहले 32 बिट्स लिखने के बाद ओएस निर्णय लेता है कि एक और प्रक्रिया सीपीयू समय प्राप्त करने जा रही है।
  • अगली प्रक्रिया उस वैरिएबल को पढ़ने का प्रयास करती है जिसे आप असाइन करने के बीच में थे।

यह 32 बिट प्लेटफॉर्म पर 64-बिट असाइनमेंट के साथ केवल एक संभावित दौड़ स्थिति है।

हालांकि, 32 बिट वैरिएबल के साथ भी पढ़ने और लिखने के साथ दौड़ की स्थिति हो सकती है क्योंकि किसी भी साझा चर को इन दौड़ स्थितियों को हल करने के लिए किसी तरह से सिंक्रनाइज़ किया जाना चाहिए।

+0

"32-बिट x86 प्लेटफार्म पर स्मृति का सबसे बड़ा परमाणु आकार का टुकड़ा 32-बिट है।" - यह गलत है। आप fstp/mmx/sse के माध्यम से परमाणु रूप से 8-बाइट लिख सकते हैं। –

0

क्या यह वाकई सच है?हाँ, जैसा कि यह निकलता है। यदि आपके रजिस्टरों में केवल 32 बिट हैं, और आपको कुछ स्मृति स्थान पर 64-बिट मान स्टोर करने की आवश्यकता है, तो इसमें दो लोड ऑपरेशंस और दो स्टोर ऑपरेशन होंगे। यदि आपकी प्रक्रिया इन दो लोड/स्टोर्स के बीच किसी अन्य प्रक्रिया द्वारा बाधित हो जाती है, तो दूसरी प्रक्रिया आपके डेटा को दूषित कर सकती है! अजीब बात है लेकिन सच है। यह कभी भी बनाए गए प्रत्येक प्रोसेसर पर एक समस्या रही है - यदि आपका डेटाटाइप आपके रजिस्टरों से अधिक लंबा है, तो आपके पास समेकन संबंधी समस्याएं होंगी।

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

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

2

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

उदाहरण के लिए:

class Program 
{ 
    public static Int64 UnsafeSharedData; 
    public static Int64 SafeSharedData; 

    static void Main(string[] args) 
    { 
     Action<Int32> unsafeAdd = i => { UnsafeSharedData += i; }; 
     Action<Int32> unsafeSubtract = i => { UnsafeSharedData -= i; }; 
     Action<Int32> safeAdd = i => Interlocked.Add(ref SafeSharedData, i); 
     Action<Int32> safeSubtract = i => Interlocked.Add(ref SafeSharedData, -i); 

     WaitHandle[] waitHandles = new[] { new ManualResetEvent(false), 
              new ManualResetEvent(false), 
              new ManualResetEvent(false), 
              new ManualResetEvent(false)}; 

     Action<Action<Int32>, Object> compute = (a, e) => 
              { 
               for (Int32 i = 1; i <= 1000000; i++) 
               { 
                a(i); 
                Thread.Sleep(0); 
               } 

               ((ManualResetEvent) e).Set(); 
              }; 

     ThreadPool.QueueUserWorkItem(o => compute(unsafeAdd, o), waitHandles[0]); 
     ThreadPool.QueueUserWorkItem(o => compute(unsafeSubtract, o), waitHandles[1]); 
     ThreadPool.QueueUserWorkItem(o => compute(safeAdd, o), waitHandles[2]); 
     ThreadPool.QueueUserWorkItem(o => compute(safeSubtract, o), waitHandles[3]); 

     WaitHandle.WaitAll(waitHandles); 
     Debug.WriteLine("Unsafe: " + UnsafeSharedData); 
     Debug.WriteLine("Safe: " + SafeSharedData); 
    } 
} 

परिणाम:

असुरक्षित: -२४०५०२७५६४१ सुरक्षित: 0

एक दिलचस्प ओर ध्यान दें पर, मैं इस भाग गया Vista 64 पर x64 मोड में। यह दिखाता है कि 64 बिट फ़ील्ड रनटाइम द्वारा 32 बिट फ़ील्ड की तरह व्यवहार किया जाता है, यानी, 64 बिट ऑपरेशंस गैर-परमाणु हैं। किसी को पता है कि यह एक सीएलआर मुद्दा है या एक x64 मुद्दा है?

+0

जैसा कि जॉन स्कीट और बेन एस ने इंगित किया था, दौड़ की स्थिति पढ़ने और लिखने के बीच हो सकती है, इसलिए आप यह नहीं समझ सकते कि लेखन गैर-परमाणु थे। –

+0

मुझे समझ में नहीं आता ... वह तर्क किसी भी तरह से जाता है। जहां तक ​​मैं कह सकता हूं, डेटा अभी भी गलत है। यदि आप उदाहरण चलाते हैं, तो यह स्पष्ट है कि गैर-परमाणु संचालन के कारण डेटा गलत हो जाता है। – codekaizen

+0

मुद्दा न तो सीएलआर या x64। यह आपके कोड के साथ है। आप जो करने की कोशिश कर रहे हैं वह परमाणु पढ़ने + जोड़/घटाना + लिखना है। जबकि x64 में आपको int64 के परमाणु पढ़ने/लिखने की गारंटी है। फिर, यह परमाणु पढ़ने + जोड़ने + लिखने से अलग है। –

12

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

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

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

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