2012-09-11 37 views
5

माइक्रोसॉफ्ट विजुअल सी ++ में मैं एक void * पैरामीटर के साथ फ़ंक्शन शुरू करके थ्रेड बनाने के लिए CreateThread() को कॉल कर सकता हूं। मैं एक पैरामीटर को उस पैरामीटर के रूप में एक पॉइंटर पास करता हूं, और मुझे लगता है कि बहुत सारे लोग भी ऐसा करते हैं।सी ++ - क्या थ्रेड को पास किया गया डेटा अस्थिर हो सकता है?

मेरा सवाल यह है कि अगर मैं अपनी संरचना में एक पॉइंटर पास कर रहा हूं तो मुझे कैसे पता चलेगा कि निर्माण सदस्यों को वास्तव में CreateThread() से पहले स्मृति में लिखा गया है या नहीं? क्या कोई गारंटी है कि उन्हें सिर्फ कैश नहीं किया जाएगा? उदाहरण के लिए:

struct bigapple { string color; int count; } apple; 
apple.count = 1; 
apple.color = "red"; 
hThread = CreateThread(NULL, 0, myfunction, &apple, 0, NULL); 

DWORD WINAPI myfunction(void *param) 
{ 
    struct bigapple *myapple = (struct bigapple *)param; 

    // how do I know that apple's struct was actually written to memory before CreateThread? 
    cout << "Apple count: " << myapple->count << endl; 
} 

इस दोपहर जब मैं पढ़ रहा था मैं इस वेबसाइट और दूसरों है कि डेटा में गुजरता है कि एक धागा करने के लिए अस्थिर नहीं है पर Windows कोड का एक बहुत कुछ देखा था, और वहाँ किसी भी स्मृति होना प्रतीत नहीं होता है बाधा या कुछ और। मुझे सी ++ पता है या कम से कम पुराने संशोधन "थ्रेड जागरूक" नहीं हैं इसलिए मैं सोच रहा हूं कि शायद कुछ और कारण है। मेरा अनुमान है कि संकलक यह देखता है कि मैंने CreateThread() को कॉल में एक पॉइंटर & सेब पास कर दिया है, इसलिए यह कॉल से पहले apple के सदस्यों को लिखना जानता है।

धन्यवाद

+0

आप प्रिंट से पहले धागे से जुड़ें हैं ?! –

+1

यह सी है, सी ++ नहीं ('संरचना बड़े आकार *'?) –

उत्तर

5

नहीं: अन्य धागा समाप्ति के लिए प्रतीक्षा करने के लिए आप मुख्य थ्रेड सिर्फ

WaitForSingleObject(hthread,INFINITE); 

कॉल करने के लिए तो मुख्य थ्रेड अधिक ठीक हो जाएगा होगा प्रासंगिक Win32 थ्रेड फ़ंक्शन सभी आवश्यक स्मृति बाधाओं का ख्याल रखते हैं। CreateThread से पहले सभी लिखते हैं नए धागे के लिए दृश्यमान हैं। स्पष्ट रूप से उस नव निर्मित धागे में पढ़ने को CreateThread पर कॉल करने से पहले पुन: व्यवस्थित नहीं किया जा सकता है।

volatile कंपाइलर पर कोई अतिरिक्त उपयोगी बाधा नहीं डालेगा, और केवल कोड को धीमा कर देगा। अभ्यास में एक नया धागा बनाने की लागत की तुलना में थिवी ध्यान देने योग्य नहीं होगा, हालांकि।

+0

+1 मुझे वास्तव में इसकी आवश्यकता नहीं है (आप और रेमंड मेरे लिए कम से कम प्राथमिक स्रोत हैं: पी) लेकिन मुझे लगता है ओपी उचित रूप से सोच सकता है [उद्धरण वांछित] ... – Mehrdad

+0

क्या होगा अगर धागे में मैं सेब-> गिनती = 2. असाइन करना था। जब धागा समाप्त हो जाता है (मेरे कार्य से सामान्य वापसी के माध्यम से) यह गारंटी है कि 2 स्मृति में लिखा गया था स्थान और सेब-> गिनती? और इसके अलावा कॉलिंग कोड "एहसास" करता है? उदाहरण के लिए मान लें कि CreateThread() कॉल सफल है और मैं अगली पंक्ति 'WaitForSingleObject (hThread, INFINITE);', और अगले 'cout << apple-> गिनती << endl;', यह गारंटी है कि गणना 2 के रूप में पढ़ी जाएगी और 1 कैश नहीं है? धन्यवाद। – loop

+0

@ मेहरदाद: उदाहरण देखें http://msdn.microsoft.com/en-us/library/windows/desktop/ms686355(v=vs.85).aspx – MSalters

1

सबसे पहले, मुझे लगता है कि अनुकूलक शुद्धता की कीमत पर आदेश नहीं बदल सकते। CreateThread() एक फ़ंक्शन है, फ़ंक्शन कॉल के लिए पैरामीटर बिनिडिंग कॉल से पहले होता है।

दूसरा, अस्थिर आपके इच्छित उद्देश्य के लिए बहुत उपयोगी नहीं है। Check out this article

+3

पहला वाक्य स्पष्ट रूप से सत्य है। अगर संकलक शुद्धता तोड़ता है तो एक कंपाइलर ऑर्डर नहीं बदल सकता है। लेकिन सही क्या है? यह हमेशा आपकी अपेक्षा नहीं हो सकता है। उदाहरण के लिए, दूसरी वाक्य ऐसी गलत धारणा दिखाती है। 'Apple.count' को लिखना पैरामीटर बाध्यकारी का हिस्सा नहीं है और इसे 'और सेब' के सापेक्ष पुन: व्यवस्थित किया जा सकता है। – MSalters

+0

@MSalters ठीक है लेकिन फिर फ़ंक्शन पैरामीटर के रूप में एक संरचना में पॉइंटर पास करने का उचित तरीका क्या है और पता है कि कैली वैध डेटा पर काम करेगा? एक पल के लिए धागे को खारिज करना, अगर मैं 'mystruct.myvar = myval करता हूं; myfunc (और mystruct); 'मैं इस धारणा के तहत था कि myfunc() हमेशा myvar के रूप में myvar पढ़ा जाएगा। क्या वो सही है? – loop

+0

@test: धागे को खारिज करना, यह काम करता है क्योंकि धागे के भीतर पुनर्गठन थ्रेड अर्थशास्त्र को तोड़ नहीं देगा। धागे में ऐसा करने का उचित तरीका एक स्मृति बाधा है। ये थ्रेड सिंक्रनाइज़ेशन फ़ंक्शंस में शामिल हैं। जैसे विंडोज के लिए, एक गंभीर खंड के साथ 'सेब' तक पहुंच की सुरक्षा करने से आवश्यक स्मृति बाधाओं को भी संभाला जाएगा। – MSalters

2

नहीं, यह volatile नहीं होना चाहिए। साथ ही आप वैध मुद्दे पर इशारा कर रहे हैं। इंटेल/एआरएम/आदि पत्रों में कैश का विस्तृत संचालन वर्णित है।

फिर भी आप सुरक्षित रूप से मान सकते हैं कि डेटा लिखा जाएगा। अन्यथा बहुत सी चीजें तोड़ दी जाएंगी। कई दशकों के अनुभव बताते हैं कि ऐसा है।

यदि थ्रेड शेड्यूलर उसी कोर पर धागा शुरू करेगा, तो कैश की स्थिति ठीक रहेगी, अन्यथा, यदि नहीं, तो कर्नेल कैश फ्लश करेगा। अन्यथा, कुछ भी काम नहीं करेगा।

धागे के बीच बातचीत के लिए कभी भी volatile का उपयोग न करें। यह केवल एक थ्रेड के अंदर डेटा को संभालने के तरीके पर एक निर्देश है (एक रजिस्टर प्रति का उपयोग करें या हमेशा रीड, आदि)।

+1

इस के साथ पूरी तरह से सहमत हुए।डेटा समेकन खतरे छोटी अवधि के लिए मौजूद हैं - शायद कोर घड़ी चक्र के 10s में, और अक्सर सीपीयू ऑप्टिमाइज़ेशन तंत्र जैसे लिखने वाले बैफर और कैश-प्रीफेच के कारण। एसएमपी आर्किटेक्चर जिसमें कोर के बीच कैश साझा नहीं किए जाते हैं, संदर्भ स्विच (जो बहुत महंगा है) पर फ्लशिंग पर निर्भर होने के बजाय व्यापक कैश-स्नूपिंग व्यवस्था होती है। यह एक सुरक्षित धारणा है कि कोई भी sys-call एक अंतर्निहित स्मृति बाधा है (संभवतः यहां तक ​​कि कई आर्किटेक्चर पर विशेषाधिकार प्राप्त मोड के लिए भी स्विच)। – marko

+0

@ किरील आप क्यों कहते हैं कि कभी थ्रेड के बीच बातचीत के लिए अस्थिरता का उपयोग नहीं करते? – loop

+0

क्योंकि इसके लिए 'अस्थिर' का इरादा नहीं है। इसका उपयोग केवल उसी धागे के लिए गारंटी प्रदान करता है। यदि आपके पास 'अस्थिर int है; ख एक =; बी = ए; ', कंपाइलर को दूसरी असाइनमेंट को छोड़ने की अनुमति नहीं है। Var 'a' लाल होना चाहिए दो बार। लेकिन एक ही समय में इस var को कितने धागे पढ़ेंगे/लिखेंगे - यह पूरी तरह से निर्दिष्ट नहीं है। आप इस तरह की कोई धारणा नहीं बना सकते हैं। –

0

आप एक गैर समस्या में संघर्ष कर रहे हैं, और कम से कम दो अन्य पैदा कर रहे ...

  1. CreateThread को दी पैरामीटर के बारे में चिंता मत करो: यदि वे समय मौजूद धागा है जब तक CreateThread रिटर्न नहीं हो जाता तब तक वे मौजूद होते हैं। और चूंकि जो धागा उन्हें बनाता है उन्हें नष्ट नहीं करता है, वे अन्य धागे के लिए भी उपलब्ध हैं।
  2. समस्या अब हो जाता है, जो और जब वे नष्ट हो जाएगा: आप new साथ उन्हें बनाने ताकि वे उपलब्ध नहीं होगा एक delete कहा जाता है जब तक (या जब तक प्रक्रिया समाप्त हो जाता है: अच्छा स्मृति रिसाव)
  3. प्रक्रिया समाप्त जब इसकी मुख्य धागा समाप्त होता है (और अन्य सभी धागे भी ओएस द्वारा समाप्त कर दिया जाएगा!)। और आपके मुख्य में कुछ भी नहीं है जो इसे दूसरे धागे को पूरा करने की प्रतीक्षा करता है।
  4. निम्न स्तर एपीआई जैसे CreateThread फॉर्म भाषाओं का उपयोग करते समय सावधान रहें जिनके पास थिअर लाइब्रेरी भी थ्रेड के साथ इंटरफेस है। सी-रनटाइम में _beginthreadex है।यह CreateThread पर कॉल करता है और सी ++ लाइब्रेरी के लिए अन्य प्रारंभिक कार्य भी करता है जिसे आप अन्यथा याद करेंगे। कुछ सी (और सी ++) लाइब्रेरी फ़ंक्शन उन प्रारंभिकताओं के बिना ठीक से काम नहीं कर सकता है, जिन्हें रनटाइम संसाधनों को समाप्ति पर ठीक से मुक्त करने की आवश्यकता होती है। Unsing CreateThread एक संदर्भ में malloc का उपयोग करना है जहां delete को फिर सफाई के लिए उपयोग किया जाता है।

उचित मुख्य थ्रेड bnehavior होना चाहिए

// create the data 
// create the other thread 
// // perform othe task 
// wait for the oter thread to terminate 
// destroy the data 

क्या Win32 API दस्तावेज़ स्पष्ट रूप से कहते हैं कि नहीं है कि हर HANDLEwaitable है, और हो जाते हैं जब सहयोगी संसाधन मुक्त हो जाता है का संकेत दिया।

{ 
    data* pdata = new data; 
    HANDLE hthread = (HANDLE)_beginthreadex(0,0,yourprocedure, pdata,0,0); 
    WaitForSingleObject(htread,INFINITE); 
    delete pdata; 
} 

या यहाँ तक कि

{ 
    data d; 
    HANDLE hthread = (HANDLE)_beginthreadex(0,0,yourprocedure, &d,0,0); 
    WaitForSingleObject(htread,INFINITE); 
} 
0

मुझे लगता है कि प्रश्न किसी अन्य संदर्भ में मान्य है। जैसा कि अन्य ने एक संरचना का उपयोग करके इंगित किया है और सामग्री सुरक्षित है (हालांकि डेटा तक पहुंच सिंक्रनाइज़ करके होनी चाहिए)।

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

संपादित करें: मुझे लगता है कि विकी पृष्ठ पर उदाहरण के लिए एक अच्छा विवरण http://en.wikipedia.org/wiki/Volatile_variable

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

  • कोई संबंधित समस्या नहीं^_^