2008-10-28 12 views
14

संपादित करें: यहां कोड में अभी भी कुछ कीड़े हैं, और यह प्रदर्शन विभाग में बेहतर प्रदर्शन कर सकती है, लेकिन इसे ठीक करने की कोशिश करने के बजाय, रिकॉर्ड के लिए मैंने समस्या को इंटेल चर्चा समूहों में लिया और महान प्रतिक्रिया के बहुत सारे मिल गया है, और अगर सब कुछ ठीक परमाणु नाव के एक पॉलिश संस्करणक्या यह परमाणु फ्लोट सुरक्षित के लिए यह C++ कार्यान्वयन सुरक्षित है?

ठीक है यहाँ एक कठिन एक, मैं एक परमाणु नाव चाहते है, के लिए नहीं इंटेल की थ्रेडिंग बिल्डिंग ब्लॉक्स के पास भविष्य के रिलीज में शामिल किया जाएगा सुपर-फास्ट ग्राफिक्स प्रदर्शन, लेकिन नियमित रूप से कक्षाओं के डेटा-सदस्यों के रूप में उपयोग करने के लिए। और मैं इन वर्गों पर ताले का उपयोग करने की कीमत का भुगतान नहीं करना चाहता, क्योंकि यह मेरी आवश्यकताओं के लिए कोई अतिरिक्त लाभ नहीं प्रदान करता है।

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

कोई भी यहां जानता है कि यह थ्रेडिंग थ्रेशिंग का कोई रूप नहीं है?

typedef unsigned int uint_32; 

    struct AtomicFloat 
    { 
    private: 
    tbb::atomic<uint_32> atomic_value_; 

    public: 
    template<memory_semantics M> 
    float fetch_and_store(float value) 
    { 
     const uint_32 value_ = atomic_value_.tbb::atomic<uint_32>::fetch_and_store<M>((uint_32&)value); 
     return reinterpret_cast<const float&>(value_); 
    } 

    float fetch_and_store(float value) 
    { 
     const uint_32 value_ = atomic_value_.tbb::atomic<uint_32>::fetch_and_store((uint_32&)value); 
     return reinterpret_cast<const float&>(value_); 
    } 

    template<memory_semantics M> 
    float compare_and_swap(float value, float comparand) 
    { 
     const uint_32 value_ = atomic_value_.tbb::atomic<uint_32>::compare_and_swap<M>((uint_32&)value,(uint_32&)compare); 
     return reinterpret_cast<const float&>(value_); 
    } 

    float compare_and_swap(float value, float compare) 
    { 
     const uint_32 value_ = atomic_value_.tbb::atomic<uint_32>::compare_and_swap((uint_32&)value,(uint_32&)compare); 
     return reinterpret_cast<const float&>(value_); 
    } 

    operator float() const volatile // volatile qualifier here for backwards compatibility 
    { 
     const uint_32 value_ = atomic_value_; 
     return reinterpret_cast<const float&>(value_); 
    } 

    float operator=(float value) 
    { 
     const uint_32 value_ = atomic_value_.tbb::atomic<uint_32>::operator =((uint_32&)value); 
     return reinterpret_cast<const float&>(value_); 
    } 

    float operator+=(float value) 
    { 
     volatile float old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<float&>(atomic_value_); 
      new_value_ = old_value_ + value; 
     } while(compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); 
    } 

    float operator*=(float value) 
    { 
     volatile float old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<float&>(atomic_value_); 
      new_value_ = old_value_ * value; 
     } while(compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); 
    } 

    float operator/=(float value) 
    { 
     volatile float old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<float&>(atomic_value_); 
      new_value_ = old_value_/value; 
     } while(compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); 
    } 

    float operator-=(float value) 
    { 
     return this->operator+=(-value); 
    } 

    float operator++() 
    { 
     return this->operator+=(1); 
    } 

    float operator--() 
    { 
     return this->operator+=(-1); 
    } 

    float fetch_and_add(float addend) 
    { 
     return this->operator+=(-addend); 
    } 

    float fetch_and_increment() 
    { 
     return this->operator+=(1); 
    } 

    float fetch_and_decrement() 
    { 
     return this->operator+=(-1); 
    } 
    }; 

धन्यवाद!

संपादित करें: बदली हुई size_t uint32_t के रूप में ग्रेग रोजर्स का सुझाव दिया, कि जिस तरह से अपने अधिक पोर्टेबल

संपादित करें: पूरे बात के लिए लिस्टिंग कहा, कुछ सुधारों के साथ।

अधिक संपादन: प्रदर्शन बुद्धिमान एक बंद नाव का उपयोग कर 5.000.000 + = मेरी मशीन पर 100 धागे के साथ संचालन के लिए 3.6s लेता है, जबकि यहां तक ​​कि अपने मूर्खतापूर्ण do-, जबकि साथ अपने परमाणु नाव 0.2s लेता भी ऐसा ही करने काम। तो> 30x प्रदर्शन बढ़ावा का अर्थ यह इसके लायक है, (और यह पकड़ है) यदि यह सही है।

और भी संपादन: जैसा कि अज्ञान ने मेरी fetch_and_xxxx भागों को इंगित किया था, सभी गलत थे। एपीआई के हिस्सों को फिक्स्ड और हटा दिया गया है, मुझे यकीन नहीं है (टेम्पलेट मेमोरी मॉडल)। और कोड पुनरावृत्ति से बचने के लिए ऑपरेटर + = के संदर्भ में अन्य परिचालनों को कार्यान्वित किया

जोड़ा गया: ऑपरेटर * = और ऑपरेटर/= जोड़ा गया, क्योंकि फ्लोट उनके बिना तैरता नहीं होगा। Peterchen की टिप्पणी के लिए धन्यवाद है कि इस देखा गया था

संपादित करें: कोड का नवीनतम संस्करण इस प्रकार है (मैं पुराने संस्करण में संदर्भ के लिए हालांकि छोड़ देंगे)

#include <tbb/atomic.h> 
    typedef unsigned int  uint_32; 
    typedef __TBB_LONG_LONG  uint_64; 

    template<typename FLOATING_POINT,typename MEMORY_BLOCK> 
    struct atomic_float_ 
    { 
    /* CRC Card ----------------------------------------------------- 
    | Class:   atmomic float template class 
    | 
    | Responsability: handle integral atomic memory as it were a float, 
    |     but partially bypassing FPU, SSE/MMX, so it is 
    |     slower than a true float, but faster and smaller 
    |     than a locked float. 
    |      *Warning* If your float usage is thwarted by 
    |     the A-B-A problem this class isn't for you 
    |      *Warning* Atomic specification says we return, 
    |     values not l-values. So (i = j) = k doesn't work. 
    | 
    | Collaborators: intel's tbb::atomic handles memory atomicity 
    ----------------------------------------------------------------*/ 
    typedef typename atomic_float_<FLOATING_POINT,MEMORY_BLOCK> self_t; 

    tbb::atomic<MEMORY_BLOCK> atomic_value_; 

    template<memory_semantics M> 
    FLOATING_POINT fetch_and_store(FLOATING_POINT value) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::fetch_and_store<M>((MEMORY_BLOCK&)value); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    FLOATING_POINT fetch_and_store(FLOATING_POINT value) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::fetch_and_store((MEMORY_BLOCK&)value); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    template<memory_semantics M> 
    FLOATING_POINT compare_and_swap(FLOATING_POINT value, FLOATING_POINT comparand) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::compare_and_swap<M>((MEMORY_BLOCK&)value,(MEMORY_BLOCK&)compare); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    FLOATING_POINT compare_and_swap(FLOATING_POINT value, FLOATING_POINT compare) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::compare_and_swap((MEMORY_BLOCK&)value,(MEMORY_BLOCK&)compare); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    operator FLOATING_POINT() const volatile // volatile qualifier here for backwards compatibility 
    { 
     const MEMORY_BLOCK value_ = atomic_value_; 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    //Note: atomic specification says we return the a copy of the base value not an l-value 
    FLOATING_POINT operator=(FLOATING_POINT rhs) 
    { 
     const MEMORY_BLOCK value_ = atomic_value_.tbb::atomic<MEMORY_BLOCK>::operator =((MEMORY_BLOCK&)rhs); 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    //Note: atomic specification says we return an l-value when operating among atomics 
    self_t& operator=(self_t& rhs) 
    { 
     const MEMORY_BLOCK value_ = atomic_value_.tbb::atomic<MEMORY_BLOCK>::operator =((MEMORY_BLOCK&)rhs); 
     return *this; 
    } 

    FLOATING_POINT& _internal_reference() const 
    { 
     return reinterpret_cast<FLOATING_POINT&>(atomic_value_.tbb::atomic<MEMORY_BLOCK>::_internal_reference()); 
    } 

    FLOATING_POINT operator+=(FLOATING_POINT value) 
    { 
     FLOATING_POINT old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<FLOATING_POINT&>(atomic_value_); 
      new_value_ = old_value_ + value; 
     //floating point binary representation is not an issue because 
     //we are using our self's compare and swap, thus comparing floats and floats 
     } while(self_t::compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); //return resulting value 
    } 

    FLOATING_POINT operator*=(FLOATING_POINT value) 
    { 
     FLOATING_POINT old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<FLOATING_POINT&>(atomic_value_); 
      new_value_ = old_value_ * value; 
     //floating point binary representation is not an issue becaus 
     //we are using our self's compare and swap, thus comparing floats and floats 
     } while(self_t::compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); //return resulting value 
    } 

    FLOATING_POINT operator/=(FLOATING_POINT value) 
    { 
     FLOATING_POINT old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<FLOATING_POINT&>(atomic_value_); 
      new_value_ = old_value_/value; 
     //floating point binary representation is not an issue because 
     //we are using our self's compare and swap, thus comparing floats and floats 
     } while(self_t::compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); //return resulting value 
    } 

    FLOATING_POINT operator-=(FLOATING_POINT value) 
    { 
     return this->operator+=(-value); //return resulting value 
    } 

    //Prefix operator 
    FLOATING_POINT operator++() 
    { 
     return this->operator+=(1); //return resulting value 
    } 

    //Prefix operator 
    FLOATING_POINT operator--() 
    { 
     return this->operator+=(-1); //return resulting value 
    } 

    //Postfix operator 
    FLOATING_POINT operator++(int) 
    { 
     const FLOATING_POINT temp = this; 
     this->operator+=(1); 
     return temp//return resulting value 
    } 

    //Postfix operator 
    FLOATING_POINT operator--(int) 
    { 
     const FLOATING_POINT temp = this; 
     this->operator+=(1); 
     return temp//return resulting value 
    } 

    FLOATING_POINT fetch_and_add(FLOATING_POINT addend) 
    { 
     const FLOATING_POINT old_value_ = atomic_value_; 
     this->operator+=(addend); 
     //atomic specification requires returning old value, not new one as in operator x= 
     return old_value_; 
    } 

    FLOATING_POINT fetch_and_increment() 
    { 
     const FLOATING_POINT old_value_ = atomic_value_; 
     this->operator+=(+1); 
     //atomic specification requires returning old value, not new one as in operator x= 
     return old_value_; 
    } 

    FLOATING_POINT fetch_and_decrement() 
    { 
     const FLOATING_POINT old_value_ = atomic_value_; 
     this->operator+=(-1); 
     //atomic specification requires returning old value, not new one as in operator x= 
     return old_value_; 
    } 
    }; 

    typedef atomic_float_<float,uint_32> AtomicFloat; 
    typedef atomic_float_<double,uint_64> AtomicDouble; 
+0

ऑपरेटर के लिए यह थोड़ा बुरा है = एक मूल्य वापस करने के लिए, क्योंकि बिल्टिन प्रकारों पर यह एक लाभा (टी और जहां टी प्रकार है) का मूल्यांकन करता है। उन प्रकारों के लिए "(i = j) = k" असामान्य लेकिन कानूनी है, और i के मान को असाइन करता है I –

+0

एक अच्छा बिंदु, और उत्तर में कोड के मेरे नवीनतम संस्करण में संबोधित किया।हालांकि टी को वापस करना और ऑपरेटर के लिए lvalue नहीं है = टीबीबी में परमाणु मूल्यों के लिए सही व्यवहार है। –

+0

हे @RobertGould। कार्यक्षमता को लागू करने और इसे साझा करने के लिए बहुत बहुत धन्यवाद। मेरे पास दो प्रश्न हैं: (1) क्या समय अभी भी वैध हैं? मेरा मतलब है, मेरे प्लेटफॉर्म पर, जब मैं 'std :: mutex' के विपरीत परमाणु संस्करण का उपयोग करता हूं, तो मुझे स्पीड-अप नहीं मिल सकता है, (2) क्या कोड के इस टुकड़े के लिए कुछ लाइसेंस है? अगर मैं इसे उधार लेना चाहता हूं और इसे अपनी परियोजना के लिए मानक पुस्तकालय में 'std :: atomic' के साथ काम करना चाहता हूं तो मुझे क्या करना चाहिए? –

उत्तर

5

मैं गंभीर रूप से सार्वजनिक विरासत के खिलाफ सलाह दूंगा। मुझे नहीं पता कि परमाणु कार्यान्वयन कैसा है, लेकिन मुझे लगता है कि यह ओवरलोडेड ऑपरेटर है जो इसे अभिन्न प्रकार के रूप में उपयोग करते हैं, जिसका अर्थ यह है कि उन प्रचारों का उपयोग कई (शायद अधिकतर) मामलों में आपके फ्लोट के बजाय किया जाएगा।

मैं किसी भी कारण है कि वह काम नहीं होता नहीं दिख रहा है, लेकिन आप की तरह मुझे लगता है कि साबित करने के लिए जिस तरह से करने के लिए है ...

एक नोट: अपने operator float() दिनचर्या, लोड प्राप्त अर्थ विज्ञान नहीं है और इसे कॉन्स अस्थिर चिह्नित नहीं किया जाना चाहिए (या निश्चित रूप से कम से कम कॉन्स)?

संपादित करें: यदि आप ऑपरेटर प्रदान करने जा रहे हैं -() आपको दोनों उपसर्ग/पोस्टफिक्स फ़ॉर्म प्रदान करना चाहिए।

+1

संरचना करना संभवतः बेहतर समाधान है। यदि कार्यान्वयन ठीक है तो मुझे शायद कक्षा को दोबारा सुधारना चाहिए। –

+0

पूरी तरह से विरासत - रचना के साथ सहमत हैं। – xtofl

3

ऐसा लगता है कि अपने कार्यान्वयन हो जाती है जैसे कि sizeof(size_t) == sizeof(float)। क्या यह हमेशा आपके लक्षित प्लेटफार्मों के लिए सच होगा?

और मैं नहीं कहूँगा इतना के रूप में विधर्म सूत्रण कास्टिंग विधर्म। :)

+0

अच्छी तरह से जरूरी नहीं है, लेकिन मैं एक स्थिर जोर देने की योजना बना रहा हूं जो संकलन के लिए एक गार्ड के रूप में आकार (फ्लोट) == आकार (आकार_टी) की तुलना करता है –

+0

यह आपको केवल uint32_t का उपयोग करने पर क्या लाभ देता है? –

+0

अच्छा दोस्त मेरे दोस्त! –

0

उस कोड को पढ़ने से, मैं इस तरह के एक कंपाइलर में वास्तव में पागल हो गया था क्योंकि इस पर असेंबली नहीं थी।

0

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

दुर्भाग्यवश, मुझे यकीन नहीं है कि विपरीत भी सच है - एकल निर्देश निर्देश परमाणु होने की गारंटी है। मैं उस स्तर पर मल्टीप्रोसेसर प्रोग्रामिंग के ब्योरे को नहीं जानता। मैं किसी भी परिणाम के लिए एक मामला बना सकता था। (यदि किसी और के पास उस पर कुछ निश्चित जानकारी है, तो इसमें शामिल होने के लिए स्वतंत्र महसूस करें।)

+0

सिंगल एएसएम निर्देशों को अन्यथा साबित होने तक गैर-परमाणु माना जाना चाहिए, विशेष रूप से x86 और अन्य CISCy आर्किटेक्चर पर, क्योंकि एक निर्देश माइक्रो-ऑप्स में टूट जाता है, betwixt जिसमें आपके पास संदर्भ स्विच हो सकता है। तुलनात्मक और स्वैप जैसे परमाणु insns इस elide अक्षम करने के लिए अक्षम। –

+0

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

+0

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

1

यह कोड की स्थिति है क्योंकि यह अब इंटेल बोर्डों पर वार्ता के बाद खड़ा है, लेकिन अभी भी काम पर पूरी तरह से सत्यापित नहीं किया गया है सभी परिदृश्यों में सही ढंग से।

#include <tbb/atomic.h> 
    typedef unsigned int  uint_32; 
    typedef __TBB_LONG_LONG  uint_64; 

    template<typename FLOATING_POINT,typename MEMORY_BLOCK> 
    struct atomic_float_ 
    { 
    /* CRC Card ----------------------------------------------------- 
    | Class:   atmomic float template class 
    | 
    | Responsability: handle integral atomic memory as it were a float, 
    |     but partially bypassing FPU, SSE/MMX, so it is 
    |     slower than a true float, but faster and smaller 
    |     than a locked float. 
    |      *Warning* If your float usage is thwarted by 
    |     the A-B-A problem this class isn't for you 
    |      *Warning* Atomic specification says we return, 
    |     values not l-values. So (i = j) = k doesn't work. 
    | 
    | Collaborators: intel's tbb::atomic handles memory atomicity 
    ----------------------------------------------------------------*/ 
    typedef typename atomic_float_<FLOATING_POINT,MEMORY_BLOCK> self_t; 

    tbb::atomic<MEMORY_BLOCK> atomic_value_; 

    template<memory_semantics M> 
    FLOATING_POINT fetch_and_store(FLOATING_POINT value) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::fetch_and_store<M>((MEMORY_BLOCK&)value); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    FLOATING_POINT fetch_and_store(FLOATING_POINT value) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::fetch_and_store((MEMORY_BLOCK&)value); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    template<memory_semantics M> 
    FLOATING_POINT compare_and_swap(FLOATING_POINT value, FLOATING_POINT comparand) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::compare_and_swap<M>((MEMORY_BLOCK&)value,(MEMORY_BLOCK&)compare); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    FLOATING_POINT compare_and_swap(FLOATING_POINT value, FLOATING_POINT compare) 
    { 
     const MEMORY_BLOCK value_ = 
      atomic_value_.tbb::atomic<MEMORY_BLOCK>::compare_and_swap((MEMORY_BLOCK&)value,(MEMORY_BLOCK&)compare); 
     //atomic specification requires returning old value, not new one 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    operator FLOATING_POINT() const volatile // volatile qualifier here for backwards compatibility 
    { 
     const MEMORY_BLOCK value_ = atomic_value_; 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    //Note: atomic specification says we return the a copy of the base value not an l-value 
    FLOATING_POINT operator=(FLOATING_POINT rhs) 
    { 
     const MEMORY_BLOCK value_ = atomic_value_.tbb::atomic<MEMORY_BLOCK>::operator =((MEMORY_BLOCK&)rhs); 
     return reinterpret_cast<const FLOATING_POINT&>(value_); 
    } 

    //Note: atomic specification says we return an l-value when operating among atomics 
    self_t& operator=(self_t& rhs) 
    { 
     const MEMORY_BLOCK value_ = atomic_value_.tbb::atomic<MEMORY_BLOCK>::operator =((MEMORY_BLOCK&)rhs); 
     return *this; 
    } 

    FLOATING_POINT& _internal_reference() const 
    { 
     return reinterpret_cast<FLOATING_POINT&>(atomic_value_.tbb::atomic<MEMORY_BLOCK>::_internal_reference()); 
    } 

    FLOATING_POINT operator+=(FLOATING_POINT value) 
    { 
     FLOATING_POINT old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<FLOATING_POINT&>(atomic_value_); 
      new_value_ = old_value_ + value; 
     //floating point binary representation is not an issue because 
     //we are using our self's compare and swap, thus comparing floats and floats 
     } while(self_t::compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); //return resulting value 
    } 

    FLOATING_POINT operator*=(FLOATING_POINT value) 
    { 
     FLOATING_POINT old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<FLOATING_POINT&>(atomic_value_); 
      new_value_ = old_value_ * value; 
     //floating point binary representation is not an issue becaus 
     //we are using our self's compare and swap, thus comparing floats and floats 
     } while(self_t::compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); //return resulting value 
    } 

    FLOATING_POINT operator/=(FLOATING_POINT value) 
    { 
     FLOATING_POINT old_value_, new_value_; 
     do 
     { 
      old_value_ = reinterpret_cast<FLOATING_POINT&>(atomic_value_); 
      new_value_ = old_value_/value; 
     //floating point binary representation is not an issue because 
     //we are using our self's compare and swap, thus comparing floats and floats 
     } while(self_t::compare_and_swap(new_value_,old_value_) != old_value_); 
     return (new_value_); //return resulting value 
    } 

    FLOATING_POINT operator-=(FLOATING_POINT value) 
    { 
     return this->operator+=(-value); //return resulting value 
    } 

    //Prefix operator 
    FLOATING_POINT operator++() 
    { 
     return this->operator+=(1); //return resulting value 
    } 

    //Prefix operator 
    FLOATING_POINT operator--() 
    { 
     return this->operator+=(-1); //return resulting value 
    } 

    //Postfix operator 
    FLOATING_POINT operator++(int) 
    { 
     const FLOATING_POINT temp = this; 
     this->operator+=(1); 
     return temp//return resulting value 
    } 

    //Postfix operator 
    FLOATING_POINT operator--(int) 
    { 
     const FLOATING_POINT temp = this; 
     this->operator+=(1); 
     return temp//return resulting value 
    } 

    FLOATING_POINT fetch_and_add(FLOATING_POINT addend) 
    { 
     const FLOATING_POINT old_value_ = atomic_value_; 
     this->operator+=(addend); 
     //atomic specification requires returning old value, not new one as in operator x= 
     return old_value_; 
    } 

    FLOATING_POINT fetch_and_increment() 
    { 
     const FLOATING_POINT old_value_ = atomic_value_; 
     this->operator+=(+1); 
     //atomic specification requires returning old value, not new one as in operator x= 
     return old_value_; 
    } 

    FLOATING_POINT fetch_and_decrement() 
    { 
     const FLOATING_POINT old_value_ = atomic_value_; 
     this->operator+=(-1); 
     //atomic specification requires returning old value, not new one as in operator x= 
     return old_value_; 
    } 
    }; 

    typedef atomic_float_<float,uint_32> AtomicFloat; 
    typedef atomic_float_<double,uint_64> AtomicDouble; 
1

हालांकि एक uint32_t का आकार एक दिया मेहराब पर एक नाव की है कि के बराबर हो सकता है, दूसरे में एक से एक डाली पुनर्व्याख्या द्वारा आप परोक्ष मानते हैं कि परमाणु वेतन वृद्धि, decrements और सभी बिट्स पर अन्य ऑपरेशंस अर्थात् दोनों प्रकारों के बराबर हैं, जो वास्तविकता में नहीं हैं। मुझे संदेह है कि यह उम्मीद के अनुसार काम करता है।

+0

नहीं, नहीं, मैं नहीं हूं, यही कारण है कि मैं वास्तविक संचालन को एक लेनदेन-जबकि-लूप (एक ज्ञात समांतर पैटर्न) में खींच रहा हूं। वैसे भी मैं आपको आश्वस्त कर सकता हूं कि कोड एक थ्रेड में सही तरीके से काम करता है। और यह मल्टीथ्रेड में भी सही ढंग से काम कर रहा है। बस यकीन नहीं है कि अगर ऐसा कुछ है तो मैं भरोसा कर सकता हूं .. –

+0

मैंने ऑपरेटरों पर अधिक ध्यान नहीं दिया। लेकिन सवाल यह है: क्या आप सुनिश्चित हैं कि fetch_and_add, fetch_and_increment आदि सही तरीके से काम कर रहे हैं? –

+0

आप सही हैं! मैंने वास्तव में उनसे ज्यादा विचार नहीं किया था क्योंकि मैं ऑपरेटरों का परीक्षण कर रहा था। Fetch_xxxx सभी गलत हैं! मूर्खतापूर्ण मुझे याद आया, उन्हें ऑपरेटरों के समान उपचार की आवश्यकता है। –

1

मुझे दृढ़ता से संदेह है कि आपको fetch_and_add आदि में सही मान मिलते हैं, क्योंकि फ्लोट अतिरिक्त int int से अलग है।

यहाँ मैं क्या इन arithmetics से प्राप्त होते हैं:

1 + 1 = 1.70141e+038 
100 + 1 = -1.46937e-037 
100 + 0.01 = 1.56743e+038 
23 + 42 = -1.31655e-036 

तो, हाँ, threadsafe नहीं बल्कि आप क्या उम्मीद करते हैं।

ताला मुक्त एल्गोरिदम (ऑपरेटर + आदि) atomicity के बारे में काम करना चाहिए (कलन विधि के लिए ही की जाँच नहीं की है ..)


अन्य समाधान: यह सब परिवर्धन और subtractions है के रूप में, आप प्रत्येक धागे को अपना उदाहरण दे सकते हैं, फिर कई धागे से परिणाम जोड़ें।

+0

नोट मैं ऐसा नहीं कर रहा हूं। मैं इनट्स को फ्लोट रेफरी में कास्टिंग कर रहा हूं, जिसका मतलब है कि उन्हें सही तरीके से संभाला जाता है। old_value_ = reinterpret_cast (* यह); new_value_ = old_value_ + मान; –

+0

यह "कम करने" के लिए समाधान के लिए ठीक होगा, लेकिन मुझे डेटा संरचनाओं (गुणों) के सदस्यों के रूप में फ़्लोट की आवश्यकता है जो लंबे जीवन में हैं। लेकिन आपकी टिप्पणी मुझे याद दिलाती है कि फ्लोट गुणा और विभाजन के बिना मूर्ख हैं। उन्हें भी जोड़ने के लिए –

+0

संशोधित कोड बहुत बेहतर दिखता है! :) और हाँ, लॉक-फ्री लूप मेरे लिए ठीक दिखते हैं, लेकिन मैंने वास्तव में उन लोगों के साथ पर्याप्त नहीं किया है जो वास्तव में न्याय करते हैं। – peterchen

1

इस बारे में सिर्फ एक नोट (मैं एक टिप्पणी करना चाहता था लेकिन स्पष्ट रूप से नए उपयोगकर्ताओं को टिप्पणी करने की अनुमति नहीं है): संदर्भों पर reinterpret_cast का उपयोग करके जीसीसी 4.1-ओ 3 के साथ गलत कोड उत्पन्न होता है। ऐसा लगता है कि यह 4.4 में तय किया गया है क्योंकि यह काम करता है। Reinterpret_casts को पॉइंटर्स में बदलना, जबकि थोड़ा उलझन, दोनों मामलों में काम करता है।

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