2017-12-05 1 views
2

を使用して:C++ - 異なる同時behaviousこのプログラムを考えると地元の人やグローバル

#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から充当されます。 現在の状態では、期待どおりに動作し、両方のスレッドが数値を指定しない順にスタックにプッシュし、スタックを正しい順序で印刷します。スレッドのデフォルトラムダキャプチャを指定するかどうかに関係なく動作します。しかし、スタックxの宣言をmain()に移動すると、プログラムはスタックの内容を出力するときにsegfaultに実行されます。 GDBは、最後にループのnod->dataにアクセスし、info localsを実行するとgdbがクラッシュすることが起こっていると言います。何が起こっている?なぜそれは違いを生みますか?

答えて

3

あなたのコードのどこにあるのですか?headメンバーは初期化されていますか? オブジェクトをグローバル変数(main以上の関数)として作成すると、headには0の値が設定されますが、main関数のスタックオブジェクトをローカル変数として作成すると、headには迷惑データランダム値が入ります。 cppreference.com

1からデフォルトコンストラクタについて

)デフォルトコンストラクタは簡単です:何の初期化は、静的およびスレッドローカルオブジェクトのゼロ初期化以外の場所を取りません。初期化を完了するためにstd :: atomic_initを使用できます。

+1

バグが私は無駄にしているcppreferenceのhttp://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange でもあります初期化されていないアトミックをデバッグするのに時間がかかっていて、コンパイラがそれについて警告していないことがあります。 cppcheckもそれを検出しませんでした。 – lars

0

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; 
     } 
    }; 
関連する問題