【发布时间】:2016-08-10 08:42:25
【问题描述】:
#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
在我看来,结果不是预期的: 注意事项 等于
我对上面的代码有一个很大的问题。
特别是,$1 行中的比较让我很头疼。我的意思是,这个比较总是返回 false,尽管它应该在第一次返回 true。
我很困惑,所以我查看了empty 和head 的内存,实际上它们是不同的。 head 等于 0x00000000 0x00000000 0x00000000 0x00000000 (当涉及到字节时),它似乎没问题。但是empty 等于:
0x00000000 0x00000000 0x00000000 0x7f7f7f7f7f。更有趣的是$2中的next等于0x00000000 0x00000000 0x00000000 0x00000000所以实际上等于head。但是,例如,curr、incrementedNext 等于 0x00000000 0x00000000 0x00000000 0x7f7f7f7f7f。
所以这种行为是不确定的,所以我想有任何未定义的行为,但为什么呢?我做错了什么,请解释一下这种行为。
附:我知道$4 中的内存泄漏,但现在我忽略了它。
我编译它:
g++ -latomic main.cpp -std=c++14。
我的 gcc 版本是 6.1.0。我也在 gcc 5.1.0 上进行了测试。结果是一样的。
@PeterCordes 创建的源链接:https://godbolt.org/g/X02QV8
【问题讨论】:
-
好吧,您可以随时编辑原始帖子,直到它正确为止。
-
我只是复制/粘贴您的代码并编译它,它适用于我:example。我可以建议您编写编译器版本和编译代码的命令吗?
-
@Gilgamesz 我刚刚用
g++ -m32 -g -o test test.cpp -latomic编译(gcc 6.1)并且它工作正常。使用调试器并查看内存时尝试启用调试标志(-g)。 -
@BiagioFesta: Baseline x86-64 没有
cmpxchg16b,因此需要使用-mcx16来启用它(或者它作为-march=haswell的一部分启用,或者-march=nativeon除了最古老的 CPU 之外的任何东西)。如果您不这样做,gcc 会发出对库函数的调用。您可以使用-latomic来避免链接错误。
标签: c++ c++11 x86 undefined-behavior stdatomic