इस धागे के आधार पर OpenMP and STL vector, कौन सा डेटा संरचना के लिए अच्छे विकल्प हैं std :: वेक्टर लूप के समानांतर में साझा किए गए हैं? मुख्य पहलू गति है, और वेक्टर को लूप के दौरान आकार बदलने की आवश्यकता हो सकती है।सी ++ ओपनएमपी समानांतर लूप के लिए विकल्प - std :: वेक्टर
उत्तर
आपके द्वारा लिंक किया गया सवाल इस तथ्य के बारे में बात कर रहा था कि "एसटीएल वेक्टर कंटेनर उस स्थिति में थ्रेड-सुरक्षित नहीं है जहां एकाधिक धागे एक कंटेनर को लिखते हैं"। यह केवल सत्य है, जैसा कि सही तरीके से कहा गया है, यदि आप उन विधियों को कॉल करते हैं जो std::vector
धारण करने वाले अंतर्निहित सरणी के पुनर्वितरण का कारण बन सकते हैं। push_back()
, pop_back()
और insert()
इन खतरनाक तरीकों के उदाहरण हैं।
यदि आपको थ्रेड सुरक्षित रीयलोकेशन की आवश्यकता है, तो लाइब्रेरी intel thread building block आपको concurrent vector containers प्रदान करती है। आपको एकल थ्रेड प्रोग्राम्स में tbb :: concurrent_vector का उपयोग नहीं करना चाहिए क्योंकि यादृच्छिक तत्वों तक पहुंचने में लगने वाला समय std :: वेक्टर ऐसा करने के लिए होता है (जो ओ (1) है)। हालांकि, समवर्ती वेक्टर push_back()
, pop_back()
, insert()
को थ्रेड सुरक्षित तरीके से कॉल करता है, भले ही पुनर्वसन होता है।
संपादित करें 1: स्लाइड 46 और the following Intel presentation 47 का उपयोग कर TBB :: concurrent_vector
संपादित 2 समवर्ती पुनः आबंटन की एक उदाहराणदर्शक उदाहरण दे: यदि आप इंटेल चलने बिल्डिंग ब्लॉक का उपयोग शुरू वैसे, (यह खुला स्रोत है , यह अधिकांश कंपाइलर्स के साथ काम करता है और यह ओपनएमपी की तुलना में सी ++/सी ++ 11 फीचर्स के साथ बहुत बेहतर एकीकृत है), तो आपको parallel_for बनाने के लिए openmp का उपयोग करने की आवश्यकता नहीं है, Here tbb का उपयोग करके parallel_for का एक अच्छा उदाहरण है।
मुझे लगता है कि आप ओपनएमपी के साथ अधिकांश समय std::vector
का उपयोग कर सकते हैं और अभी भी अच्छा प्रदर्शन कर सकते हैं। उदाहरण के लिए निम्नलिखित कोड समानांतर में std::vectors
भरता है और फिर अंत में उन्हें जोड़ता है। जब तक आपका मुख्य पाश/भरने का कार्य बाधा है, तब तक इसे सामान्य रूप से अच्छी तरह से काम करना चाहिए और थ्रेड सुरक्षित होना चाहिए।
std::vector<int> vec;
#pragma omp parallel
{
std::vector<int> vec_private;
#pragma omp for nowait //fill vec_private in parallel
for(int i=0; i<100; i++) {
vec_private.push_back(i);
}
#pragma omp critical
vec.insert(vec.end(), vec_private.begin(), vec_private.end());
}
संपादित करें:
OpenMP 4.0 उपयोगकर्ता परिभाषित #pragma omp declare reduction
का उपयोग कर में कटौती की अनुमति देता है। उपरोक्त कोड
#pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))
std::vector<int> vec;
#pragma omp parallel for reduction(merge: vec)
for(int i=0; i<100; i++) vec.push_back(i);
के लिए संपादित करें के साथ सरल किया जा सकता: मैं अब तक क्या पता चला है क्रम में वेक्टर भर नहीं। आदेश मामलों तो यह इस
std::vector<int> vec;
#pragma omp parallel
{
std::vector<int> vec_private;
#pragma omp for nowait schedule(static)
for(int i=0; i<N; i++) {
vec_private.push_back(i);
}
#pragma omp for schedule(static) ordered
for(int i=0; i<omp_get_num_threads(); i++) {
#pragma omp ordered
vec.insert(vec.end(), vec_private.begin(), vec_private.end());
}
}
की तरह किया जा सकता है, तो यह प्रत्येक थ्रेड के लिए एक std :: वेक्टर बचत और फिर उन्हें समानांतर क्षेत्र के धारावाहिक के बाहर में विलय से बचा जाता है। मैंने इस "चाल" here के बारे में सीखा। मुझे यकीन नहीं है कि उपयोगकर्ता द्वारा निर्धारित कटौती के लिए यह कैसे करें (या यदि यह भी संभव है)।। उपयोगकर्ता परिभाषित कटौती के साथ ऐसा करना संभव नहीं है।
मुझे अभी एहसास हुआ कि महत्वपूर्ण अनुभाग आवश्यक नहीं है जिसे मैंने इस प्रश्न से parallel-cumulative-prefix-sums-in-openmp-communicating-values-between-thread से निकाला है। इस विधि को ऑर्डर सही भी है
std::vector<int> vec;
size_t *prefix;
#pragma omp parallel
{
int ithread = omp_get_thread_num();
int nthreads = omp_get_num_threads();
#pragma omp single
{
prefix = new size_t[nthreads+1];
prefix[0] = 0;
}
std::vector<int> vec_private;
#pragma omp for schedule(static) nowait
for(int i=0; i<100; i++) {
vec_private.push_back(i);
}
prefix[ithread+1] = vec_private.size();
#pragma omp barrier
#pragma omp single
{
for(int i=1; i<(nthreads+1); i++) prefix[i] += prefix[i-1];
vec.resize(vec.size() + prefix[nthreads]);
}
std::copy(vec_private.begin(), vec_private.end(), vec.begin() + prefix[ithread]);
}
delete[] prefix;
अंतिम अंतिम वाक्य में प्रश्न के लिए: "किसी भी 'कमी' खंड के लिए, इन निष्पादन का आदेश निष्पादित किया गया है," इसलिए संभव नहीं है। –
- 1. सी ++ 11 ओपनएमपी के विकल्प को क्लैंग
- 2. लूप के लिए समानांतर
- 3. रेंज के लिए लूप और std :: वेक्टर <bool>
- 4. आकार() std :: वेक्टर (सी ++)
- 5. सी ++ - एक std :: वेक्टर में ऑब्जेक्ट्स को जोड़ना, लूप
- 6. सी ++: 'std :: is_fundamental' के विकल्प?
- 7. मल्टी-आयामी नेस्टेड ओपनएमपी लूप
- 8. लूप के लिए ओपनएमपी और सी समानांतर: OpenMP का उपयोग करते समय मेरा कोड धीमा क्यों होता है?
- 9. ओपनएमपी
- 10. सी ++ 2011: std :: thread: लूप को समानांतर करने के लिए सरल उदाहरण?
- 11. समानांतर लूप
- 12. ओपनएमपी नेस्टेड लूप कैसे संभालता है?
- 13. लूप/for_each के लिए प्रत्येक इटरेशन समानांतर में किया जा सकता है? (सी ++ 11)
- 14. सी ++ std :: वेक्टर emplace बनाम
- 15. std वेक्टर सी ++ - गहरी या उथली प्रतिलिपि
- 16. समांतर क्षेत्र में लूप के लिए ओपनएमपी पुनरावृत्ति
- 17. समानांतर के लिए प्राथमिकता सेट करें। लूप
- 18. ओपनएमपी
- 19. ओपनएमपी
- 20. ओपनएमपी "मास्टर" प्रगामा को "समानांतर" प्रगामा
- 21. क्या वेक्टर से तत्वों को निकालने के लिए std :: remove_if का बेहतर विकल्प है?
- 22. 2 डी std :: वेक्टर
- 23. एक समानांतर लूप को समानांतर में बदलना। फोरएच लूप
- 24. दूरी गणना के लिए समानांतर सी कोड
- 25. लूप चर के समानांतर में क्यों हस्ताक्षर किए जाने चाहिए?
- 26. समानांतर फॉरएच या लूप
- 27. समानांतर for_each std :: for_each
- 28. std :: वेक्टर स्ट्रिंग करने के लिए
- 29. सी ++ वेक्टर
- 30. नेस्टेड लूप में ओपनएमपी के ओवरहेड से कैसे बचें
हमें कुछ कोड दिखाएं, अपनी विशिष्ट स्थिति का वर्णन करें ... वेक्टर में क्या संग्रहीत किया जाएगा? आपका लूप इसके साथ क्या करेगा? यह बहुत संभव है कि वैसे भी 'std :: vector' का उपयोग करने के लिए यह पूरी तरह से सुरक्षित होगा। – LihO
जैसा कि जुड़े हुए थ्रेड में कहा गया है, आपको केवल अपने लूप में, जब आपके वेक्टर का आकार बदल रहा है, और संभावित रूप से फिर से आवंटित किया गया है, तो आपको केवल std :: वेक्टर का उपयोग न करने की आवश्यकता है। यदि आप वस्तुओं को बदलते हैं, तो आप इसे पूरी तरह से ठीक से उपयोग कर सकते हैं। क्या आप अपनी आवश्यकताओं पर विस्तार कर सकते हैं, और क्यों वेक्टर आपकी आवश्यकताओं को पूरा नहीं करेगा? – SinisterMJ
मुझे लगता है कि यह केवल एक समस्या है यदि 'std :: vector' साझा किया जाता है। यदि यह निजी है तो मुझे नहीं लगता कि 'push_back' या' आकार बदलें 'का उपयोग करने में कोई समस्या है। –