2012-02-08 25 views
34

मैं चाहता हूं कि मेरा धागा अधिक सुन्दरता से बंद हो जाए, इसलिए मैं एक सरल सिग्नलिंग तंत्र को लागू करने की कोशिश कर रहा हूं। मुझे नहीं लगता कि मैं एक पूरी तरह से घटना चालित धागा चाहते हैं तो मैं एक विधि के साथ एक कार्यकर्ता एक महत्वपूर्ण खंड Monitor का उपयोग कर इसे रोकने graceully करने के लिए (एक सी # lock के बराबर मेरा मानना ​​है कि) क्या है:क्या कोई अन्य धागा इसे सेट कर सकता है (अधिकतर बार) इसे लॉक किए बिना साझा बूलियन ध्वज को पढ़ना ठीक है?

DrawingThread.h

class DrawingThread { 
    bool stopRequested; 
    Runtime::Monitor CSMonitor; 
    CPInfo *pPInfo; 
    //More.. 
} 

DrawingThread.cpp

void DrawingThread::Run() { 
    if (!stopRequested) 
     //Time consuming call#1 
    if (!stopRequested) { 
     CSMonitor.Enter(); 
     pPInfo = new CPInfo(/**/); 
     //Not time consuming but pPInfo must either be null or constructed. 
     CSMonitor.Exit(); 
    } 
    if (!stopRequested) { 
     pPInfo->foobar(/**/);//Time consuming and can be signalled 
    } 
    if (!stopRequested) { 
     //One more optional but time consuming call. 
    } 
} 


void DrawingThread::RequestStop() { 
    CSMonitor.Enter(); 
    stopRequested = true; 
    if (pPInfo) pPInfo->RequestStop(); 
    CSMonitor.Exit(); 
} 

मैं समझता हूँ (कम से कम Windows में) Monitor/lock रों कम से कम महंगा धागा तुल्यकालन आदिम हैं, लेकिन मैं अति प्रयोग से बचने के लिए उत्सुक हूँ। क्या मुझे इस बुलियन ध्वज के प्रत्येक पढ़ने को लपेटना चाहिए? इसे झूठी शुरूआत की जाती है और जब स्टॉप का अनुरोध किया जाता है तो केवल एक बार सत्य पर सेट किया जाता है (यदि कार्य पूरा होने से पहले अनुरोध किया जाता है)।

मेरे ट्यूटर्स ने bool की रक्षा करने की सलाह दी क्योंकि पढ़ना/लेखन परमाणु नहीं हो सकता है। मुझे लगता है कि यह एक शॉट ध्वज अपवाद है जो नियम साबित करता है?

+1

अपने शिक्षक की सलाह लें (वे शायद सही हैं) - भले ही वे नहीं हैं वे आपके काम को चिह्नित कर रहे हैं, इसलिए यदि वे कहते हैं कि इसकी आवश्यकता है तो इसकी आवश्यकता है। – John3136

+6

@ जॉन 3136 मेरा शिक्षक की सलाह 10 साल पुरानी है, यह मेरा काम है। – John

उत्तर

38

सिंक्रनाइज़ेशन के बिना किसी भिन्न थ्रेड में संभावित रूप से संशोधित कुछ पढ़ने के लिए कभी भी ठीक नहीं है। सिंक्रनाइज़ेशन की किस स्तर की आवश्यकता है उस पर निर्भर करता है कि आप वास्तव में क्या पढ़ रहे हैं। आदिम प्रकारों के लिए, आपको परमाणु पढ़ने पर एक नज़र रखना चाहिए, उदा। std::atomic<bool> के रूप में।

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

+0

मुझे नहीं लगता कि मेरे प्लेटफॉर्म में 'std :: atomic' शामिल है। – John

+1

'std :: atomic ' सी ++ 2011 का हिस्सा है। यह आम तौर पर मंच के प्रदत्त सुविधाओं के शीर्ष पर लागू होता है जो सम्मान मंच पर जो कुछ भी चुना जाता है उसके साथ आता है। प्रभावी रूप से इसमें उचित प्रोसेसर ऑपरेशन का उपयोग करना शामिल है। इन्हें कैसे बुलाया जाता है और इस्तेमाल प्लेटफॉर्म पर निर्भर करता है। 'std :: atomic 'उन्हें एक अच्छा और पोर्टेबल इंटरफेस देता है। –

+0

यह 'सीएस मॉनिटर' के साथ पहुंच की रक्षा करने के लिए मेरे लिए कहीं अधिक रखरखाव होगा क्योंकि मैं इससे बचने की कोशिश कर रहा था। तो मैं यहां सुरक्षित रूप से उपेक्षित नहीं कर सकता हूं, यहां तक ​​कि 'अस्थिर बूल स्टॉप रिक्वेस्टेड' के साथ भी, क्योंकि उस मान को सीपीयू में कैश किया जा सकता है और मॉनिटर किए गए एक्सेसर, 'RequestStop' के माध्यम से भी अपडेट की अनजान हो सकती है, जब तक कि इसे किसी महत्वपूर्ण अनुभाग में पढ़ा नहीं जा रहा हो? – John

10

बूलियन असाइनमेंट परमाणु है। यह समस्या नहीं है।

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

समाधान एक स्मृति बाड़ है, जो वास्तव में लॉक स्टेटमेंट द्वारा स्पष्ट रूप से जोड़ा जाता है, लेकिन एक चर के लिए यह अधिक है। बस इसे volatile घोषित करें।

+1

"बूलियन असाइनमेंट परमाणु है": बस ब्याज से बाहर, क्या यह सी या सी ++ मानक द्वारा आवश्यक है? –

+16

ध्यान दें कि सी ++ में कुछ 'अस्थिर' घोषित करने के लिए ** ** ** ** ** ** सिंक्रनाइज़ेशन ** पर प्रभाव नहीं है **! 'अस्थिर' का उपयोग संकलक के लिए इसे छोड़ने और/या निर्देशों को पुन: निर्देशित करने से रोकने के लिए है (यह जावा में 'अस्थिर' के अर्थशास्त्र के लिए अलग है। आपको सीपीयू को यह बताने की भी आवश्यकता है कि सिंक्रनाइज़ेशन की आवश्यकता है। आपको संबंधित निर्देश का उपयोग करने की आवश्यकता है, उदा। 'std :: परमाणु '। –

+2

@ निकलासबी। मुझे लगता है कि इसका मतलब क्या है: आप धागे द्वारा देखी जाने वाली 'बूल' की असंगत स्थिति के साथ समाप्त नहीं हो सकते हैं। यह वास्तव में इस अर्थ में परमाणु है। हालांकि, इसका मतलब यह नहीं है कि मूल्य अलग-अलग कोरों के साथ किसी भी तरह से सिंक्रनाइज़ किया जाता है। इन परमाणु होने के लिए आपको सिंक्रनाइज़ेशन की आवश्यकता है उदा। 'std :: परमाणु ' का उपयोग कर। –

1

नहीं, आपको हर एक्सेस की रक्षा करनी है, क्योंकि आधुनिक कंपाइलर्स और सीपीयू आपके मल्टीथ्रेडिंग कार्यों के बिना कोड को फिर से व्यवस्थित करते हैं। विभिन्न धागे से पढ़ने की पहुंच काम कर सकती है, लेकिन काम करने की ज़रूरत नहीं है।

4

उत्तर, मेरा मानना ​​है, "यह निर्भर करता है।" यदि आप सी ++ 03 का उपयोग कर रहे हैं, तो थ्रेडिंग को मानक में परिभाषित नहीं किया गया है, और आपको यह पढ़ना होगा कि आपका कंपाइलर और आपकी थ्रेड लाइब्रेरी क्या कहती है, हालांकि इस तरह की चीज को आमतौर पर "सौम्य दौड़" and is usually OK कहा जाता है।

यदि आप सी ++ 11 का उपयोग कर रहे हैं, तो सौम्य दौड़ अपरिभाषित व्यवहार हैं। यहां तक ​​कि जब अपरिभाषित व्यवहार अंतर्निहित डेटा प्रकार के लिए समझ में नहीं आता है। समस्या यह है कि संकलक यह मान सकते हैं कि प्रोग्रामों में कोई अपरिभाषित व्यवहार नहीं है, and make optimizations based on that (वहां से भाग 1 और भाग 2 भी देखें)। उदाहरण के लिए, आपका कंपाइलर एक बार ध्वज को पढ़ने और मूल्य को कैश करने का निर्णय ले सकता है क्योंकि यह किसी अन्य प्रकार के म्यूटेक्स या मेमोरी बाधा के बिना किसी अन्य थ्रेड में चर को लिखने के लिए अपरिभाषित व्यवहार है।

बेशक, यह अच्छी तरह से हो सकता है कि आपके कंपाइलर ने ऑप्टिमाइज़ेशन नहीं करने का वादा किया है। आपको देखना होगा।

सबसे आसान समाधानसी ++ 11 में या Hans Boehm's atomic_ops जैसे कहीं और उपयोग करना है।

+1

यह "निर्भर" नहीं है: यदि आपको एकाधिक धागे में म्यूटेबल डेटा साझा करने की आवश्यकता है, भले ही यह केवल 'बूल' है, तो आपको किसी प्रकार का सिंक्रनाइज़ेशन चाहिए। अनिवार्य रूप से यह सीपीयू को वर्तमान में कैश किए जाने वाले ऑब्जेक्ट्स को व्यवस्थित करने के लिए सूचित करना है। –

+1

यह इस अर्थ में निर्भर करता है कि (1) जब मानक कहता है कि कुछ अपरिभाषित है, तो कार्यान्वयन ** ** को परिभाषित करने की अनुमति है कि क्या होगा और सौम्य दौड़ इतनी आम हैं कि संकलक ऐसा कर सकता है कि एक सभ्य मौका है; और (2) जबकि सीई ++ 11 के तहत सौम्य दौड़ निश्चित रूप से अपरिभाषित हैं, यह कहना मुश्किल है कि सी ++ 03 के लिए (हालांकि पहला पेपर जो मैं लिंक करता हूं वह बिल्कुल कहता है, बेशक यह भी दिखाता है कि इन प्रकार के डेटा रेस कितने व्यापक हैं कर रहे हैं)। –