我试图使用c ++ 11原子类编写一个简单的线程安全堆栈。 这些是我到目前为止所做的。
void pushNode(Node* node) {
//
// node->_next = _head.load(std::memory_order_relaxed);
// while(!_head.compare_exchange_weak(node->_next, node));
//
// http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange
// Note: the above use is not thread-safe in at least
// GCC prior to 4.8.3 (bug 60272), clang prior to 2014-05-05 (bug 18899)
// MSVC prior to 2014-03-17 (bug 819819). The following is a workaround:
Node* head = _head.load(std::memory_order_relaxed);
do {
node->_next = head;
} while(!_head.compare_exchange_weak(head, node,
std::memory_order_release, std::memory_order_relaxed));
}
Node* popNode() {
Node* head;
Node* expected = _head.load(std::memory_order_relaxed);
do {
head = expected;
} while(head && !_head.compare_exchange_weak(expected, head->_next,
std::memory_order_release, std::memory_order_relaxed));
if(head)
head->_next = nullptr;
return head;
}
void pop() {
delete popNode();
}
private:
std::atomic<Node*> _head;
我还编写了一个测试用例,以了解这个堆栈在某些条件下的稳定性(3个线程,每个线程随机提交一百万次推送和弹出操作)。答案并不多。
测试用程序崩溃了一段时间,引发访问冲突异常,读取0xbaadf00d 0xfeeefeee 0xcdcdcdcd或其他一些无效的内存地址。
经过几天的谷歌搜索,我发现的唯一可能导致此问题的是Is std::atomic_compare_exchange_weak thread-unsafe by design。正如在代码中评论的那样,我在这里找到了一个workround std::atomic::compare_exchange_weak。不知道ms家伙是否在我的编译器(MSVC 2015社区)中摆脱了这个错误的实现,我只是应用了workround补丁。
但是没有出现魔法,测试用例像往常一样崩溃。
std :: atomic :: compare_exchange_weak是否仍然被错误地实现,或者我只是做了一些愚蠢的事情?