![](/img/trans.png)
[英]Same hierarchy, different behaviour when accessing protected member of base class
[英]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。
我很困惑,所以我期待到內存中以便empty
和head
,實際上它們是不同的。 head
等於0x00000000 0x00000000 0x00000000 0x00000000
(涉及字節),似乎還可以。 但empty
等於: 0x00000000 0x00000000 0x00000000 0x7f7f7f7f7f
。 next
在$2
更有趣的是等於0x00000000 0x00000000 0x00000000 0x00000000
所以實際上,它等於head
。 但是,例如curr
, incrementedNext
等於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.