2017-12-05 2 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; 
     } 
    };