2010-07-26 13 views
7

मेरे पास छोटे लेकिन अक्सर फ़ंक्शन ऑब्जेक्ट्स का उपयोग किया जाता है। प्रत्येक धागे की अपनी प्रति प्राप्त होती है। सबकुछ स्थिर रूप से आवंटित किया जाता है। प्रतियां किसी वैश्विक या स्थैतिक डेटा को साझा नहीं करती हैं। क्या मुझे इस ऑब्जेक्ट को झूठी साझाकरण से बचाने की ज़रूरत है?झूठी साझाकरण और ढेर चर

धन्यवाद। संपादित करें: यहां एक खिलौना प्रोग्राम है जो बूस्ट का उपयोग करता है। थ्रेड। क्षेत्र डेटा के लिए झूठी साझाकरण हो सकती है?

#include <boost/thread/thread.hpp> 

struct Work { 
    void operator()() { 
     ++data; 
    } 

    int data; 
}; 

int main() { 
    boost::thread_group threads; 
    for (int i = 0; i < 10; ++i) 
     threads.create_thread(Work()); 
    threads.join_all(); 
} 
+0

कोड बेहतर काम करेगा। यदि आपके फ़ंक्शन ऑब्जेक्ट्स में 'स्थिर' डेटा है, तो सभी थ्रेड उस डेटा को साझा करेंगे। – GManNickG

+0

सोचें कि आपको यह बताने की ज़रूरत है कि "प्रत्येक धागे की अपनी प्रतिलिपि प्राप्त होती है" और "स्थिर रूप से आवंटित" से आपका क्या मतलब है। धागे एक दूसरे की प्रतिलिपि बनाते हैं? – Elemental

+0

@Elemental: कुछ कंपाइलर टीएलएस-थ्रेड स्थानीय भंडारण का उपयोग कर सकते हैं। इसका मतलब है कि आप स्थिर और थ्रेड-सुरक्षित रूप से आवंटित कर सकते हैं, हालांकि धीमा है। – Puppy

उत्तर

6

धागे के बीच झूठी साझाकरण तब होती है जब 2 या अधिक धागे एक ही कैश लाइन का उपयोग करते हैं।

उदा। :

struct Work { 
    Work(int& d) : data(d) {} 
    void operator()() { 
     ++data; 
    } 

    int& data; 
}; 

int main() { 
    int false_sharing[10] = { 0 }; 
    boost::thread_group threads; 
    for (int i = 0; i < 10; ++i) 
     threads.create_thread(Work(false_sharing[i])); 
    threads.join_all(); 

    int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 }; 
    for (int i = 0; i < 10; ++i) 
     threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS])); 
    threads.join_all(); 
} 

पहले ब्लॉक में धागे झूठी साझाकरण से ग्रस्त हैं। दूसरे ब्लॉक में धागे नहीं (CACHELINE_SIZE के लिए धन्यवाद)।

ढेर पर डेटा हमेशा अन्य धागे से दूर 'दूर' होता है। (खिड़कियों के नीचे, कम से कम कुछ पेज)।

फ़ंक्शन ऑब्जेक्ट की आपकी परिभाषा के साथ, झूठी साझाकरण दिखाई दे सकती है, क्योंकि Work के उदाहरण ढेर पर बनाए जाते हैं और यह ढेर स्थान थ्रेड के अंदर उपयोग किया जाता है।

इससे कई Work उदाहरण सामने आ सकते हैं और इसलिए कैश लाइनों को साझा करना पड़ सकता है।

लेकिन ... आपका नमूना समझ में नहीं आता है, क्योंकि डेटा को कभी भी स्पर्श नहीं किया जाता है और इसलिए झूठी साझाकरण को बेकार ढंग से प्रेरित किया जाता है।

इस तरह की समस्याओं को रोकने के लिए सबसे आसान तरीका है, अपने 'साझा' डेटा को स्थानीय रूप से स्टैक पर कॉपी करना है, और फिर स्टैक प्रति पर काम करना है। जब आपका काम समाप्त हो जाता है तो उसे आउटपुट var पर वापस कॉपी करें।

उदा:

struct Work { 
    Work(int& d) : data(d) {} 
    void operator()() 
    { 
     int tmp = data; 
     for(int i = 0; i < lengthy_op; ++i) 
      ++tmp; 
     data = tmp; 
    } 

    int& data; 
}; 

यह साझा के साथ सभी समस्याओं से बचाता है।

+0

क्या आप कह रहे हैं कि झूठी साझाकरण से डेटा प्रभावित हो सकता है? मेरे मामले में इसे फ़ंक्शन के ढेर में कॉपी करने में सहायता नहीं होगी, क्योंकि फ़ंक्शन को स्वयं को अक्सर कॉल किया जाना चाहिए और प्रति कॉल केवल एक बार डेटा का उपयोग करना चाहिए। – user401947

+0

जब फ़ंक्शन को अक्सर बार-बार कहा जाना चाहिए, तो हर बार धागा बनाने का अर्थ नहीं होता है। या तो आप एक नए धागे में बहुत अधिक काम करते हैं, या आप थ्रेड निर्माण/विनाश के लिए चक्र जलाते हैं। और बाद के मामले में, आप धागे की भारी लागत से झूठी साझाकरण की लागत को ढंकते हैं। – Christopher

+0

फिर भी। यदि आप अपने ऑपरेशन के लिए स्टैक पर डेटा कॉपी नहीं कर सकते हैं, तो कम से कम CACHLINE_SIZE लंबे होने के लिए बस 'वर्क' पर्याप्त बनाएं। आप कुछ बाइट्स खो देते हैं, लेकिन आप वास्तव में झूठी साझाकरण समस्याओं में कभी भी भाग नहीं ले सकते हैं। – Christopher

0

मैं विवरण के साथ पूरी तरह से सुरक्षित नहीं लग रहा है, लेकिन यहाँ मेरी ले रहा है:

(1) आपका सरल उदाहरण के बाद से बढ़ावा create_thread एक संदर्भ की उम्मीद टूटी हुई है, आप एक अस्थायी गुजरती हैं।

(2) यदि आप vector<Work> का उपयोग प्रत्येक थ्रेड के लिए एक आइटम के साथ करते हैं, या अन्यथा क्रमशः स्मृति में होते हैं, तो झूठी साझाकरण होती है।

+0

(1) नहीं, यह टूटा नहीं है। create_thread मूल्य द्वारा इसके तर्क स्वीकार करता है। यदि आप मुझ पर विश्वास नहीं करते हैं तो घोषणा की जांच करें। (2) मैंने स्पष्ट रूप से कहा है कि प्रत्येक थ्रेड की अपनी प्रति प्राप्त होती है। कोड जांचें। फ़ंक्शन ऑब्जेक्ट मान द्वारा पारित किया जाता है। – user401947

+0

यह है। लक्ष्य स्टैक में काम की प्रतिलिपि नहीं बनाई गई है। यह 'create_thread' के संदर्भ में 'नया' है और लक्ष्य स्टैक पर केवल एक (साझा-) पॉइंटर स्थानांतरित किया जाता है। वहां डेटा केवल एक सूचक द्वारा संदर्भित किया जाता है। (मैंने डेटा सदस्य को थ्रेड_आईडी निर्दिष्ट करके, और फिर ऑपरेटर() कॉल में मान को देखकर इसका परीक्षण किया।) – Christopher

+0

(1) हम इस बारे में बात कर रहे हैं: 'थ्रेड * create_thread (कॉन्स बूस्ट :: function0 और थ्रेडफनक); '? संदर्भ – peterchen

2

मैंने थोड़ा सा शोध किया और ऐसा लगता है कि झूठी साझाकरण के लिए कोई चांदी बुलेट समाधान नहीं है। यहां मैं जो हूं (क्रिस्टोफर के लिए धन्यवाद): 1) अप्रयुक्त या कम अक्सर उपयोग की जाने वाली सामग्री के साथ दोनों तरफ से अपना डेटा पैड करें। 2) अपने डेटा को ढेर में कॉपी करें और सभी कड़ी मेहनत के बाद इसे वापस कॉपी करें। 3) कैश संरेखित स्मृति आवंटन का उपयोग करें।

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