2014-11-02 6 views
10

स्वाभाविक रूप से, एक परमाणु लोड या स्टोर करने के लिए एक विशिष्ट आधुनिक प्रोसेसर आर्किटेक्चर (जैसे x86_64) के क्रम में, पढ़ने/लिखे जाने वाले डेटा को गठबंधन करने की आवश्यकता होती है।परमाणु चर के संरेखण

लेकिन यह आवश्यकता वास्तव में सी ++ 11 <atomic> चर के माध्यम से कैसे लागू/लागू की जाती है?

मान लीजिए मैं एक वास्तुकला 16-बाइट तुलना और स्वैप (डबल शब्द कैस) का समर्थन करता है, तो यह atomically/16-बाइट मूल्यों लिखते हैं, और मैं एक 16-बाइट के प्रकार को परिभाषित पढ़ सकते हैं:

struct double_word 
{ 
    std::uint64_t x; 
    std::uint64_t y; 
}; 

अब, मान लीजिए मैं एक वर्ग के एक सदस्य क्षेत्र के रूप में एक std::atomic<double_word> में शामिल हैं:

class foo 
{ 
    public: 

    std::atomic<double_word> dword; 
}; 

मुझे कैसे पता चलेगा foo::dword वास्तव में एक 16-बाइट सीमा पर गठबंधन है? मुझे dword.load() पर कॉल कैसे पता चलेगा वास्तव में परमाणु होगा?

असल में, मैं मूल रूप से इस प्रश्न पूछना शुरू कर रहा था क्योंकि जब मैंने foo::dword से पहले एक और डेटा सदस्य जोड़ा था। मैं के रूप में परिभाषित किया गया foo:

class foo 
{ 
    public: 

    std::uint64_t x; 
    std::atomic<double_word> dword; 
}; 

जब मैं वास्तव में foo::dword पर एक परमाणु भार करते हैं, और संकलन और एक x86_64 डेबियन लिनक्स चल मशीन पर जीसीसी 4.7.2 का उपयोग कर चलाते हैं, तो यह वास्तव में मुझे एक विभाजन दोष देता है!

पूरा कार्यक्रम:

#include <atomic> 
#include <cstdint> 

    struct double_word 
    { 
     std::uint64_t x; 
     std::uint64_t y; 
    }; 

    class foo 
    { 
     public: 

     std::uint64_t x; 
     std::atomic<double_word> dword; // <-- not aligned on 16-byte boundary 
    }; 

    int main() 
    { 
     foo f; 
     double_word d = f.dword.load(); // <-- segfaults with GCC 4.7.2 !! 
    } 

यह वास्तव में f.dword.load() पर segfaults। सबसे पहले मुझे समझ में नहीं आया क्यों, लेकिन फिर मुझे एहसास हुआ कि dword 16-बाइट सीमा पर गठबंधन नहीं हुआ है। इसलिए, इससे बहुत सारे प्रश्न सामने आते हैं: कंपाइलर को क्या करना चाहिए यदि परमाणु चर संरेखित नहीं होता है और हम इसे परमाणु रूप से लोड करने का प्रयास करते हैं? क्या यह अनिर्धारित व्यवहार है? कार्यक्रम ने बस क्यों सीगफॉल्ट किया?

दूसरा, सी ++ 11 मानक इस बारे में क्या कहता है? क्या संकलक सुनिश्चित कर सकता है कि double_word स्वचालित रूप से 16-बाइट सीमा पर गठबंधन किया गया है? यदि हां, तो क्या इसका मतलब है कि जीसीसी बस यहां छोटी है? यदि नहीं - ऐसा लगता है कि यह संरेखण सुनिश्चित करने के लिए उपयोगकर्ता पर निर्भर करता है, जिसमें कोई समय हम एक बाइट से std::atomic<T> का उपयोग करते हैं, तो ऐसा लगता है कि std::aligned_storage का उपयोग करने के लिए यह सुनिश्चित करने के लिए कि यह ठीक से गठबंधन है , जो (ए) बोझिल लगता है, और (बी) ऐसा कुछ है जिसे मैंने वास्तव में अभ्यास में या किसी भी उदाहरण/ट्यूटोरियल में कभी नहीं देखा है।

तो, सी ++ 11 <atomic> का उपयोग कर प्रोग्रामर को इस तरह संरेखण के मुद्दों को कैसे संभालना चाहिए?

+3

यह कंपाइलर और लाइब्रेरी के बीच सहयोग की दोष की तरह दिखता है।कोड जो सी ++ मानक segfaults द्वारा काम करना चाहिए। –

+3

जीसीसी 4.7.2 पुराना है, और सी ++ 11 मानक के अंतिमकरण से पहले। कृपया [जीसीसी] (http://gcc.gnu.org/) के एक नए संस्करण पर स्विच करें (नवंबर 2014 में, [जीसीसी 4.9.2] (https://gcc.gnu.org/gcc-4.9/)) जो अधिक सी ++ 11 अनुरूप होगा। –

+0

किसी भी अन्य प्रोग्रामर की तरह, कंपाइलर मैनुअल को देखें और देखें कि कंपाइलर क्या मानता है और आपको ** ** ** क्या करना है, इसे करने के लिए आपको यह कैसे कहना चाहिए। कंपाइलर मैनुअल को देखने का एक अन्य कारण है क्योंकि उनमें चेंजलॉग और नोट्स शामिल हैं जो कि विशेषताएं पूर्ण नहीं हैं ... जैसे कि 4.7.2 में परमाणु। – BlamKiwi

उत्तर

-1

मुझे लगता है कि यह सुनिश्चित करने के लिए प्रोग्रामर की ज़िम्मेदारी है कि डॉवर्ड 16bytes संरेखण है। 64 बिट प्लेटफॉर्म पर, 64 बिट्स सीमा में डेटा गठबंधन किया जाता है जब तक आप स्पष्ट रूप से निर्दिष्ट नहीं करते हैं।

1

यह एक जीसीसी बग https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65147 बस alignas(16) जोड़ना समस्या को ठीक कर रहा है।

#include <atomic> 
#include <cstdint> 

struct double_word 
{ 
    std::uint64_t x; 
    std::uint64_t y; 
}; 

class foo 
{ 
    public: 

    std::uint64_t x; 
    alignas(16) std::atomic<double_word> dword; // <-- not aligned on 16-byte boundary 
}; 

int main() 
{ 
    foo f; 
    double_word d = f.dword.load(); // <-- segfaults with GCC 4.7.2 !! 
} 
संबंधित मुद्दे