给定此程序:
#include <thread>
#include <iostream>
#include <atomic>
template<typename T>
struct node
{
T data;
node* next;
node(const T& data) : data(data), next(nullptr) {}
};
template<typename T>
class stack {
std::atomic<node<T>*> head;
public:
void push(const T& data) {
node<T>* new_node = new node<T>(data);
new_node->next = head.load();
while(!head.compare_exchange_weak(new_node->next, new_node));
}
node<T>* get_head() {
return head;
}
};
stack<int> x;
int main() {
std::cout << "main() starts" << std::endl;
const int MAKS_OP = 100;
std::thread t1{[&]{
for (int i = 0; i < MAKS_OP; ++i) {
x.push(i);
std::string s = "Thread 1 added ";
s += std::to_string(i);
s += " to the stack!n";
std::cout << s;
}
}};
std::thread t2{[&]{
for (int i = 0; i < MAKS_OP; ++i) {
x.push(i);
std::string s = "Thread 2 added ";
s += std::to_string(i);
s += " to the stack!n";
std::cout << s;
}
}};
t1.join();
t2.join();
for (auto nod = x.get_head(); nod != nullptr; nod = nod->next) {
std::cout << nod->data << "n";
}
std::cout << "main() completesn";
}
该代码或多或少是从这里拨出的。在当前状态下,它的行为与预期的是,这两个线程都以未指定的顺序将数字推到堆栈,然后按正确的顺序打印堆栈。无论我是否指定线程的默认lambda捕获,它都可以使用。但是,当我将堆栈X的声明移动到main()中时,在打印堆栈内容时,程序会运行到segfault中。GDB告诉我,在末尾访问循环中的nod->data
并运行info locals
崩溃时,它会发生。到底是怎么回事?为什么它甚至有所作为?
我不确定,但是,在您的代码head
成员中初始化的位置?当您将对象创建为全局变量(上方main
函数)时,head
将具有0个值,但是当您将堆栈对象创建为主函数(本地变量)时,Head将包含垃圾数据 - 随机值 - 随机值。
关于cppreference.com
的默认构造函数1)默认的构造函数是微不足道的:除了静态和螺纹 - 本地对象的零初始化之外,没有进行初始化。std :: atomic_init可以用于完成初始化。
初始化std :: atomic*> head;如下所示,在堆栈构造函数中应该解决问题,
template<typename T>
class stack {
std::atomic<node<T>*> head;
public:
stack()
{
head = 0;
}
void push(const T& data) {
node<T>* new_node = new node<T>(data);
new_node->next = head.load();
while (!head.compare_exchange_weak(new_node->next, new_node));
}
node<T>* get_head() {
return head;
}
};