2012-12-23 45 views
5

मान लीजिए कि मैं एक वर्ग है कि इस (वास्तव में वास्तव में इस आकार) की तरह लग रहा है:एक साझा म्यूटेक्स अपेक्षाकृत बड़ी संरचना के परमाणु से अधिक कुशल है?

class K 
{ 
public: 

    long long get_x() const; // lock m_mutex in shared/read-only mode 

    void update(long long w); // lock m_mutex with a unique_lock 

private: 
    long long m_a; 
    long long m_b; 
    long long m_c; 
    long long m_x; 
    double m_flow_factor; 

    mutable boost::shared_mutex m_mutex; 
}; 

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

अद्यतन फ़ंक्शन सभी मानों को बदल रहा है और इसे अक्सर कहा जाता है (एक हंड्रेड समय एक सेकंड)। वर्तमान कार्यान्वयन, जैसा कि आप अनुमान लगा सकते हैं, बहुत ताले लगाएंगे।

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

class K 
{ 
public: 

    long long get_x() const 
    { return data.load().x; } 

    void update(long long w) 
    { 
     auto data_now = data.load(); 
     // ... work with data_now 
     data.store(data_now); 
    } 

private: 
    struct Data { 
    long long a; 
    long long b; 
    long long c; 
    long long x; 
    double flow_factor; 
    }; 
    std::atomic<Data> data; 
}; 

मेरे एसटीडी की वर्तमान समझ :: परमाणु कि, इस कोड को पिछले एक से अधिक पठनीय है, भले ही (क्योंकि यह ताला घोषणाओं नहीं है हर जगह), के :: डेटा स्ट्रक्चर "बड़ा" है, std :: atomic केवल सामान्य म्यूटेक्स लॉक के साथ कार्यान्वित किया जाएगा (इसलिए यह मेरे प्रारंभिक कार्यान्वयन से भी तेज़ नहीं होना चाहिए)।

क्या मैं सही हूँ?

उत्तर

8

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

साझा_म्यूटिक्स के साथ, सामान्य म्यूटेक्स बनाम साझा_म्यूटेक्स के साथ प्रोफाइल करना बुद्धिमान हो सकता है, आप सामान्य म्यूटेक्स बेहतर प्रदर्शन कर सकते हैं (यह इस बात पर निर्भर करता है कि आप कितने समय तक अपने ताले रख रहे हैं)।

साझा_म्यूटेक्स का लाभ केवल तभी देखा जाता है जब लंबे समय तक पढ़ने के लिए ताले लगाए जा रहे हैं और बहुत कम लिखते हैं, अन्यथा साझा_म्यूटेक्स में शामिल ओवरहेड सामान्य म्यूटेक्स पर आपके द्वारा प्राप्त किए गए किसी भी लाभ को मारता है।

+0

मुझे नहीं पता था कि shared_mutex के लिए ... जानकारी के लिए धन्यवाद! – Klaim

1

std :: atomic std :: mutex से ज़रूरी नहीं है। MSVC 14.0 में उदाहरण के लिए, std :: atomic.store के कार्यान्वयन इस तरह दिखता है:

inline void _Atomic_copy(
volatile _Atomic_flag_t *_Flag, size_t _Size, 
    volatile void *_Tgt, volatile const void *_Src, 
     memory_order _Order) 
{ /* atomically copy *_Src to *_Tgt with memory ordering */ 
_Lock_spin_lock(_Flag); 
_CSTD memcpy((void *)_Tgt, (void *)_Src, _Size); 
_Unlock_spin_lock(_Flag); 
} 

inline void _Lock_spin_lock(
volatile _Atomic_flag_t *_Flag) 
{ /* spin until _Flag successfully set */ 
while (_ATOMIC_FLAG_TEST_AND_SET(_Flag, memory_order_acquire)) 
    _YIELD_PROCESSOR; 
} 

यह गारंटी नहीं है कि स्पिन ताला एक उचित std :: म्युटेक्स तुलना में तेजी से हो जाएगा। यह इस बात पर निर्भर करता है कि आप वास्तव में क्या कर रहे हैं। लेकिन std :: atomic निश्चित रूप से std :: mutex की तुलना में एक उप-इष्टतम समाधान नहीं है।