C ++ - 使用locals和globals时不同的并发行为

时间:2017-12-05 09:12:33

标签: c++ multithreading global-variables

鉴于此计划:

#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() completes\n";
}

代码或多或少来自here。 在其当前状态下,它的行为完全符合预期,两个线程都以未指定的顺序将数字推送到堆栈,然后以正确的顺序打印堆栈。无论我是否为线程指定默认的lambda捕获,它都有效。但是,当我将堆栈x的声明移动到main()时,程序在打印堆栈的内容时会遇到段错误。 GDB告诉我,最后在循环中访问nod->data时会发生这种情况,并且运行info locals会导致gdb崩溃。到底是怎么回事?为什么它甚至会产生影响?

2 个答案:

答案 0 :(得分:3)

我不确定但是,您的代码head成员在哪里初始化? 当您将对象创建为全局变量时(main函数上方)head将具有0值,但是当您在main函数中创建堆栈对象作为局部变量时,head将包含垃圾数据 - 随机值。< / p>

关于cppreference.com的默认构造函数

  

1)默认构造函数是微不足道的:除了静态和线程局部对象的零初始化之外,不会发生任何初始化。 std :: atomic_init可用于完成初始化。

答案 1 :(得分:0)

初始化std :: atomic *&gt;头;在堆栈构造函数中,如下所示,那应该解决问题,

    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;
        }
    };