2009-09-22 15 views
13

मुझे हाल ही में पता चला था कि थ्रेड स्थानीय भंडारण कुछ प्लेटफार्मों पर सीमित है। उदाहरण के लिए, सी ++ लाइब्रेरी बूस्ट :: थ्रेड के लिए दस्तावेज़:कौन से प्लेटफॉर्म थ्रेड स्थानीय स्टोरेज सीमित हैं और कितना उपलब्ध है?

"नोट: थ्रेड विशिष्ट स्टोरेज ऑब्जेक्ट्स की संख्या के लिए एक कार्यान्वयन विशिष्ट सीमा है जिसे बनाया जा सकता है, और यह सीमा छोटी हो सकती है।"

मैं विभिन्न प्लेटफ़ॉर्म के लिए सीमाओं को खोजने और खोजने के लिए खोज कर रहा हूं, लेकिन मैं एक आधिकारिक तालिका नहीं ढूंढ पा रहा हूं। यह एक महत्वपूर्ण सवाल है यदि आप एक क्रॉसप्लेटफार्म ऐप लिख रहे हैं जो टीएलएस का उपयोग करता है। लिनक्स एकमात्र प्लेटफार्म था जिसे मैंने पाया था, 2002 में एक पैच इनगो मोनर को कर्नेल सूची में टीएलएस समर्थन जोड़ने के लिए भेजा गया था, जहां उन्होंने उल्लेख किया था, "टीएलएस क्षेत्रों की संख्या असीमित है, और अतिरिक्त आवंटन ओवरहेड नहीं है टीएलएस समर्थन से जुड़े। " जो 200 9 में अभी भी सच है (है ना?) बहुत निफ्टी है।

लेकिन आज लिनक्स के बारे में क्या? ओएस एक्स? विंडोज? सोलारिस? एम्बेडेड ओएसईएस? कई आर्किटेक्चर पर चलने वाले ओएस के लिए यह आर्किटेक्चर में भिन्न होता है?

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

उत्तर

0

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

3

मैं केवल Windows पर टीएलएस का इस्तेमाल किया है, और वहाँ कितना इस्तेमाल किया जा सकता में संस्करणों के बीच मामूली अंतर हैं: http://msdn.microsoft.com/en-us/library/ms686749(VS.85).aspx

मुझे लगता है कि अपने कोड है केवल थ्रेड का समर्थन करने वाले ऑपरेटिंग सिस्टम को लक्षित करना - अतीत में मैंने एम्बेडेड और डेस्कटॉप ओएस के साथ काम किया है जो थ्रेडिंग का समर्थन नहीं करते हैं, इसलिए टीएलएस का समर्थन न करें।

9

लिनक्स, यदि आप __thread टीएलएस डेटा का उपयोग कर रहे हैं, केवल सीमा आपकी उपलब्ध पता स्थान से, सेट किया गया है के रूप में इस डेटा बस (x86 पर) gs द्वारा संदर्भित नियमित रैम या fs (x86-64 पर के रूप में आवंटित किया जाता है) सेगमेंट डिस्क्रिप्टर। ध्यान दें कि, कुछ मामलों में, द्वारा उपयोग किए गए टीएलएस डेटा का आवंटन पुस्तकालयों को गतिशील रूप से लोड किया जा सकता है जो उस टीएलएस डेटा का उपयोग नहीं करते हैं।

pthread_key_create द्वारा आवंटित टीएलएस और दोस्तों, हालांकि, PTHREAD_KEYS_MAX स्लॉट तक सीमित है (यह सभी अनुरूप पठार कार्यान्वयन पर लागू होता है)।

लिनक्स पर टीएलएस इम्प्लेमेनेटेशन के बारे में अधिक जानकारी के लिए, ELF Handling For Thread-Local Storage और The Native POSIX Thread Library for Linux देखें।

यह कहा गया है कि, यदि आपको पोर्टेबिलिटी की आवश्यकता है, तो आपकी सबसे अच्छी शर्त टीएलएस उपयोग को कम करना है - टीएलएस में एक पॉइंटर डालें, और उस पॉइंटर को लटकाए गए डेटा स्ट्रक्चर में जो कुछ भी आपको चाहिए उसे डाल दें।

0

धागे की स्थानीय Windows पर भंडारण declspec यह केवल स्थैतिक चर के लिए उपयोग कर, जिसका अर्थ है आप भाग्य से बाहर हैं आप और अधिक रचनात्मक तरीके से उपयोग करना चाहते हैं, तो आप को सीमित करता है।

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

दूसरी ओर, थ्रेड-स्थानीय भंडारण के लिए pthread API अच्छी तरह से विचार-विमर्श और लचीला है।

0

धागा स्थानीय भंडारण प्रदान करने के लिए मैं एक साधारण टेम्पलेट वर्ग का उपयोग करता हूं। यह बस std::map और एक महत्वपूर्ण खंड लपेटता है। यह तब किसी प्लेटफ़ॉर्म विशिष्ट थ्रेड स्थानीय समस्याओं से ग्रस्त नहीं है, केवल मौजूदा प्लेटफ़ॉर्म आवश्यकता को वर्तमान थ्रेड आईडी को पूर्णांक में प्राप्त करना है। यह देशी धागे स्थानीय भंडारण की तुलना में थोड़ा धीमा हो सकता है लेकिन यह किसी भी डेटा प्रकार को स्टोर कर सकता है।

नीचे मेरे कोड का एक कट डाउन संस्करण है। कोड को सरल बनाने के लिए मैंने डिफ़ॉल्ट मान तर्क हटा दिया है। चूंकि यह किसी भी डेटा प्रकार को स्टोर कर सकता है, तो वृद्धि और कमी ऑपरेटर केवल तभी उपलब्ध होते हैं जब T उनका समर्थन करता है। महत्वपूर्ण खंड केवल नक्शा में दिखने और डालने की रक्षा करने के लिए आवश्यक है। एक बार संदर्भ लौटाए जाने के बाद असुरक्षित उपयोग करना सुरक्षित है क्योंकि केवल वर्तमान धागा इस मान का उपयोग करेगा।

template <class T> 
class ThreadLocal 
{ 
public: 
    operator T() 
    { 
     return value(); 
    } 

    T & operator++() 
    { 
     return ++value(); 
    } 

    T operator++(int) 
    { 
     return value()++; 
    } 

    T & operator--() 
    { 
     return --value(); 
    } 

    T operator--(int) 
    { 
     return value()--; 
    } 

    T & operator=(const T& v) 
    { 
     return (value() = v); 
    } 

private: 
    T & value() 
    { 
     LockGuard<CriticalSection> lock(m_cs); 
     return m_threadMap[Thread::getThreadID()]; 
    } 

    CriticalSection  m_cs; 
    std::map<int, T> m_threadMap; 
}; 

मैं आम तौर पर एक वर्ग जैसे अंदर एक स्थिर सदस्य की घोषणा इस वर्ग का उपयोग करने के

class DBConnection { 
    DBConnection() { 
     ++m_connectionCount; 
    } 

    ~DBConnection() { 
     --m_connectionCount; 
    } 

    // ... 
    static ThreadLocal<unsigned int> m_connectionCount; 
}; 

ThreadLocal<unsigned int> DBConnection::m_connectionCount 

यह हर स्थिति के लिए एकदम सही नहीं हो सकता है लेकिन यह मेरी जरूरत को शामिल किया गया और मैं आसानी से यह है किसी भी सुविधाओं को जोड़ सकते गायब होने के कारण मैं उन्हें खोजता हूं।

bdonlan सही है यह उदाहरण धागे के बाहर निकलने के बाद साफ़ नहीं होता है। हालांकि मैन्युअल रूप से साफ करना बहुत आसान है।

template <class T> 
class ThreadLocal 
{ 
public: 
    static void cleanup(ThreadLocal<T> & tl) 
    { 
     LockGuard<CriticalSection> lock(m_cs); 
     tl.m_threadMap.erase(Thread::getThreadID()); 
    } 

    class AutoCleanup { 
    public: 
     AutoCleanup(ThreadLocal<T> & tl) : m_tl(tl) {} 
     ~AutoCleanup() { 
      cleanup(m_tl); 
     } 

    private: 
     ThreadLocal<T> m_tl 
    } 

    // ... 
} 

फिर एक धागा जानता है कि यह ThreadLocal की स्पष्ट उपयोग इसका मुख्य कार्य में ThreadLocal::AutoCleanup का उपयोग चर को साफ कर सकते हैं बनाता है।

या DBConnection

~DBConnection() { 
    if (--m_connectionCount == 0) 
     ThreadLocal<int>::cleanup(m_connectionCount); 
} 

इतनी के रूप में operator T() साथ हस्तक्षेप न करने cleanup() विधि स्थिर है के मामले में। इसे कॉल करने के लिए एक वैश्विक फ़ंक्शन का उपयोग किया जा सकता है जो टेम्पलेट पैरामीटर का अनुमान लगाएगा।

+0

धागे के मरने के बाद यह साफ नहीं होता है ... – bdonlan

+0

आप सही हैं, वर्तमान में साफ़ करना होगा मैन्युअल रूप से करना होगा – iain

1

मैक पर, मैं Multiprocessing Services एपीआई में Task-Specific Storage के बारे में पता:

MPAllocateTaskStorageIndex 
MPDeallocateTaskStorageIndex 
MPGetTaskStorageValue 
MPSetTaskStorageValue 

यह बहुत विंडोज धागा स्थानीय भंडारण के समान दिखता है।

मुझे यकीन नहीं है कि यह API वर्तमान में मैक पर थ्रेड स्थानीय संग्रहण के लिए अनुशंसित है या नहीं। शायद कुछ नया है।