簡體   English   中英

相同類別的相同實例,但行為不同。 可能的UB

[英]The same instances of the same class but different behaviour. Probable UB

#include <iostream>

#include <atomic>
#include <memory>


template<typename T>
class LockFreeQueue {
public:
    struct CountedNode;

private:
    std::atomic<CountedNode> head;
public:
    struct Node{
        explicit Node(const T& d) : next(CountedNode()), data(std::make_shared<T>(d)), node_counter(0) { }
        std::atomic<CountedNode> next;
        std::shared_ptr<T> data;
        std::atomic<unsigned> node_counter;
    };
    struct CountedNode {
        CountedNode() noexcept : node(nullptr), counter(0) {}
        explicit  CountedNode( const T& data) noexcept : node(new Node(data) /* $4 */), counter(0)  {}
        Node* node;
        int counter;
    };


    void push( const T& data)
    {
        CountedNode new_node(data), curr, incrementedNext, next /*($2) */;
        CountedNode empty; /*($3) */
        if (head.compare_exchange_strong(empty, new_node)) std::cout << "EQUALS\n"; // $1
        else std::cout << "NOT EQUALS\n";

        if (head.compare_exchange_strong(next, new_node)) std::cout << "EQUALS\n"; // $1
        else std::cout << "NOT EQUALS\n";
    }

};


int main() {
    LockFreeQueue<int> Q;
    Q.push(2);

    return 0;
}



    int main(){
    LockFreeQueue<int> Q;
    Q.push(2);

    return 0;
    }

好。 它編譯並執行沒有錯誤。 但是,仍然存在問題,我將在下面進行描述。

http://coliru.stacked-crooked.com/a/1fe71fafc5dde518

在我看來,結果出乎意料:NOTEQUALS EQUALS

我對上面的代碼有一個瘋狂的問題。

尤其是, $1行中的比較使我成為一個問題。 我的意思是,此比較總是返回false,盡管它應該在第一時間返回true。

我很困惑,所以我期待到內存中以便emptyhead ,實際上它們是不同的。 head等於0x00000000 0x00000000 0x00000000 0x00000000 (涉及字節),似乎還可以。 empty等於: 0x00000000 0x00000000 0x00000000 0x7f7f7f7f7f next$2更有趣的是等於0x00000000 0x00000000 0x00000000 0x00000000所以實際上,它等於head 但是,例如currincrementedNext等於0x00000000 0x00000000 0x00000000 0x7f7f7f7f7f 因此,這種行為是不確定的,因此我認為任何不確定的行為,但是為什么呢? 我做錯了什么,請向我解釋這種行為。

PS我知道$4中的內存泄漏,但是現在我忽略了它。

我用以下g++ -latomic main.cpp -std=c++14編譯了它: g++ -latomic main.cpp -std=c++14 我的gcc版本是6.1.0。 我也在gcc 5.1.0上進行了測試。 結果是一樣的。

@PeterCordes創建的到源的鏈接: https ://godbolt.org/g/X02QV8

填充。 std::atomic::compare_exchange*比較兩個對象的內存表示,就像通過memcmp 如果結構具有填充,則其內容是不確定的,並且即使兩個實例在成員方面相等,也可能使兩個實例看起來不同(請注意, CountedNode甚至沒有定義operator== )。

在64位版本中, counter后面有填充,您會看到問題。 在32位版本中,沒有,而您沒有。

編輯 :我現在相信下面的部分是錯誤的; 僅保留完整性。 std::atomic_init不會做任何事情來使填充為零; 該示例似乎只是偶然地起作用。


head (以及Node::next )應該用std::atomic_init初始化:

std::atomic_init(&head, CountedNode());

完成后, 您的示例將按預期工作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM