2012-12-19 28 views
16

लिखने की थ्रेड-सुरक्षा मैंने on Stackoverflow पढ़ा है कि एसटीएल कंटेनर में से कोई भी लिखने के लिए थ्रेड-सुरक्षित नहीं है। लेकिन अभ्यास में इसका क्या अर्थ है? क्या इसका मतलब है कि मुझे सादे सरणी में लिखने योग्य डेटा स्टोर करना चाहिए?एक std :: vector बनाम सादे सरणी

मुझे उम्मीद है कि समवर्ती कॉल std::vector::push_back(element) असंगत डेटा संरचनाओं का कारण बन सकती है क्योंकि यह वेक्टर का आकार बदल सकता है। लेकिन क्या इस तरह के मामले में, जहां का आकार बदलने के शामिल नहीं है के बारे में:)

1 एक सरणी का उपयोग कर:

int data[n]; 
// initialize values here... 

#pragma omp parallel for 
for (int i = 0; i < n; ++i) { 
    data[i] += func(i); 
} 

2) एक `std :: vector`` का उपयोग कर:

std::vector<int> data; 
data.resize(n); 
// initialize values here... 

#pragma omp parallel for 
for (int i = 0; i < n; ++i) { 
    data[i] += func(i); 
} 

पहला कार्यान्वयन वास्तव में दूसरे की तुलना में बेहतर है ए) थ्रेड-सुरक्षा के मामले में और बी) प्रदर्शन के संदर्भ में? मैं एक std :: वेक्टर का उपयोग करना पसंद करूंगा, क्योंकि मैं सी-स्टाइल सरणी के साथ कम आरामदायक हूं।

संपादित करें: मैंने #pragma omp atomic update लिखने की रक्षा की है।

+1

मैं इसे उत्तर देने के लिए पर्याप्त नहीं हूं, लेकिन मुझे यकीन है कि 'std :: vector' के विभिन्न तत्वों को लिखना थ्रेड-सुरक्षित है। – Angew

+1

ये दो स्निपेट समान रूप से थ्रेड सुरक्षित हैं। –

+0

"लेकिन अभ्यास में इसका क्या अर्थ है?" : इसका मतलब है कि एक कंटेनर को विशेष रूप से दोनों लिखने के लिए लेटा जाना चाहिए * और * यदि कोई/या तो ऑपरेशन समवर्ती ** लिखने के साथ मेल खाता है तो पढ़ें। आप सभी पाठकों को अपने इच्छित कंटेनर पर टक्कर दे सकते हैं, लेकिन जैसे ही एक लेखन * संभावित * पेश किया जाता है, सभी दांव बंद हो जाते हैं और आपको * सभी * पहुंच (केवल अन्य लेखकों तक) को कम करना होगा। एक सिंगल-राइट-मल्टी-रीड लॉक इसके लिए अच्छा काम करता है, बीटीडब्ल्यू। – WhozCraig

उत्तर

22

दोनों समान रूप से सुरक्षित हैं। बशर्ते कि आप ठीक से कई धागे से कोई तत्व एक्सेस नहीं कर पाएंगे। आपका समांतर लूप प्रत्येक तत्व को केवल एक बार एक्सेस करेगा, और इसलिए केवल एक थ्रेड से।

कंटेनरों के सदस्य कार्यों के लिए मानक में जगह गैर-थ्रेड-सुरक्षित होने के लिए मानक है। इस मामले में आप vector<int>::operator[] का उपयोग करते हैं, इसलिए आप उस सदस्य के लिए थ्रेड-सुरक्षा की स्पष्ट गारंटी चाहते हैं, जो कि गैर-कॉन्स वेक्टर पर भी कॉल करने के बाद उचित लगता है, वेक्टर को स्वयं संशोधित नहीं करता है। तो मुझे संदेह है कि इस मामले में एक समस्या है, लेकिन मैंने गारंटी की तलाश नहीं की है [संपादित करें: अमीर इसे मिला]। यहां तक ​​कि यदि यह संभावित रूप से असुरक्षित है, तो आप लूप से पहले int *dataptr = &data.front() कर सकते हैं और फिर data के बजाय dataptr को इंडेक्स कर सकते हैं।

एक के रूप में एक तरफ, इस कोड नहींvector<bool> के लिए सुरक्षित की गारंटी है, क्योंकि यह एक विशेष मामला है, जिसकी कई तत्वों एक वस्तु के अंदर एक साथ नहीं हो रहा है। यह bool की सरणी के लिए सुरक्षित होगा, क्योंकि इसके विभिन्न तत्व अलग-अलग "स्मृति स्थान" (सी ++ 11 में 1.7) हैं।

+0

मैंने यह देखने के लिए एक छोटा परीक्षण फ़ंक्शन लिखा था कि ओपनएमपी सही ढंग से काम कर रहा था या नहीं। मैंने 'वेक्टर ' का उपयोग किया, इसे इस्तेमाल किए गए धागे की संख्या (झूठी शुरूआत) के आकार में बदल दिया, और सभी मानों को एक साथ सच में सेट किया। यदि प्रत्येक मान सत्य था, तो फ़ंक्शन यह दिखाने के लिए सच हो गया कि सभी धागे सही ढंग से चमक रहे थे। 'वेक्टर ' फिर से मारा गया है। सौभाग्य से, मैंने वास्तव में मानक के प्रासंगिक भाग को हाल ही में पढ़ा है, इसलिए मैं इसे समझने में सक्षम था, लेकिन अगर कोई इस पर ठोकर खाता है, तो उन्हें यह सुनिश्चित करने की ज़रूरत है कि वे 'वेक्टर ' पर समवर्ती लिखने से बचें। – Justin

+0

इसके द्वारा जाकर, यह प्रत्येक संबंधित पृथक थ्रेड से 'std :: वेक्टर >' के अंतर्गत व्यक्तिगत वैक्टरों को push_back सुरक्षित होना चाहिए? –

1

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

+5

उसका उदाहरण ओपनएमपी – nogard

+2

के माध्यम से कई धागे का उपयोग करता है। 0 को शायद यह गलत के रूप में डाउनवॉटेड किया गया था लेकिन हटाए गए संपादन से पहले पोस्ट किया गया था: #pragma omp परमाणु अद्यतन, जो समवर्ती लेखन को रोकता है और इस उत्तर को संदर्भ में सही बनाता है मूल पोस्ट –

1

इस मामले में आपको केवल अपने वेक्टर को आवश्यक संख्या के साथ बनाना चाहिए? और सब ठीक काम करेंगे।

std::vector<int> data(n, 0); 

resize() अच्छी तरह से काम करता है। प्रदर्शन बराबर होगा। मल्टीथ्रेड पहुंच वेक्टर को भ्रष्ट नहीं करने का कारण है: आपका डेटा इसकी जगह पर स्थित है और वहां से नहीं चलेगा। ओएमपी थ्रेड एक ही समय में एक ही तत्व तक नहीं पहुंच पाएंगे।

17

सी ++ 11 के लिए, जो डेटा दौड़ के नियमों को निर्दिष्ट करता है, कंटेनरों की थ्रेड-सुरक्षा का वर्णन किया गया है। मानक का एक प्रासंगिक खंड § 23.2.2 है, अनुच्छेद 2:

इसके बावजूद (17.6.5।9), डेटा रेस से बचने के लिए कार्यान्वयन की आवश्यकता होती है जब वेक्टर < बूल > को छोड़कर, उसी अनुक्रम में अलग-अलग तत्वों में निहित ऑब्जेक्ट की सामग्री को समवर्ती रूप से संशोधित किया जाता है।

[नोट: एक वेक्टर <int> x एक से अधिक आकार के साथ, x [1] = 5 और * x.begin() = 10 डेटा रेस के बिना समवर्ती रूप से निष्पादित किया जा सकता है, लेकिन x [0] = 5 और * x.begin() = 10 निष्पादित रूप से निष्पादित डेटा परिणामस्वरूप हो सकता है। सामान्य नियम के अपवाद के रूप में, वेक्टर < बूल > वाई, वाई [0] = सत्य वाई [1] = सत्य के साथ दौड़ सकता है। अंत टिप्पणी]

उल्लेख § 17.6.5.9 अनिवार्य रूप से किसी भी मानक पुस्तकालय इंटरफ़ेस द्वारा किसी भी समवर्ती संशोधन पर रोक लगाई जब तक कि विशेष अनुमति है, तो खंड मैं बोली आपको बताता है कि वास्तव में क्या अनुमति दी गई है (और है कि अपने उपयोग भी शामिल है)। डेटा दौड़ से परहेज (17.6.5.9) के प्रयोजनों के कार्यान्वयन के लिए

:

के बाद से सवाल स्टीव जेसप, § 23.2.2 के अनुच्छेद 1 के द्वारा उठाया गया था स्पष्ट रूप से अनुक्रम कंटेनरों में [] का साथ-साथ उपयोग की अनुमति देता निम्न कार्यों को कॉन्स के रूप में मानेंगे: प्रारंभिक या अनियंत्रित सहयोगी कंटेनर, ऑपरेटर [] को छोड़कर, प्रारंभ, अंत, rbegin, rend, front, back, data, find, lower_bound, upper_bound, equal_range, और, पर।