2016-09-16 1 views
4

는 잠금이없는 스택 구현이 나열됩니다이 자물쇠가없는 스택 클래스의 '삭제'노드가 경쟁 조건을 유발하는 이유는 무엇입니까? 7.2.1 절에서 앤서니 윌리엄스 "액션 C++ 동시성"라는 제목의 책에서

template <typename T> 
class lock_free_stack { 
    struct node { 
     shared_ptr<T> data_; 
     node* next_; 
     node(const T& data) : data_(make_shared(data)) {} 
    }; 
    atomic<node*> head_; 
public: 
    void push(const T& data) 
    { 
     node* new_node = new node(data); 
     new_node->next_ = head_.load(); 
     while(!head.compare_exchange_weak(new_node->next_, new_node)); 
    } 
    shared_ptr<T> pop() 
    { 
     node* old_head = head_.load(); 
     while (old_head && 
       !head_.compare_exchange_weak(old_head, head_->next_)); 
     return old_head ? old_head->data_ : shared_ptr<T>(); 
    } 
}; 

다음 섹션 7.2.2에서, 저자는 말한다. " .. pop()에서 우리는 하나의 스레드가 노드를 삭제하는 경쟁 조건을 피하기 위해 노드 누설을 선택했다. 반면 다른 스레드는 아직 참조 해제하려고하는 포인터를 보유하고있다. "

1) 다음과 같은 팝업() 함수 경쟁 조건이 발생할 왜 이러한 시나리오가 일어날 이유를 이해하지 않습니다

shared_ptr<T> pop() 
{ 
    node* old_head = head_.load(); // (1) 
    while (old_head && 
      !head_.compare_exchange_weak(old_head, head_->next_)); // (2) 
    shared_ptr<T> res; // (3) 
    if (old_head) { 
     res.swap(old_head->data); 
     delete old_head; 
     return res; 
    } else { 
     return {}; 
    } 
} 

2) 어떻게 오는 팝업을 호출 다중 스레드() 동시에 'old_head'변수는 line (3) 뒤에 동일한 노드 객체를 가리킬 수 있습니까?

답변

8

스레드 1은 (2)로 진행됩니다. 그것은 head_->next을 평가하기 시작합니다. 레지스터에 head_을로드 한 다음 우선 순위를 포기합니다.

스레드 2는 함수의 처음부터 끝까지 진행됩니다. 삭제를 통해 head_을 존재에서 제거하고 head_의 내용을 반환합니다.

스레드 1이 깨어납니다. ->next 필드를 가져 오는 레지스터에 head_이옵니다. 그러나 스레드 2는 이미 head_이 가리키는 데이터를 삭제했으며, 우리는 매달린 포인터를 따라갔습니다.

+0

죄송합니다. 아직 명확하지 않습니다. 예, 스레드 1은 현존하지 않는 포인터를 따라가고 다른 변수에 이미 할당 된 "다음"에 값을 읽습니다. 따라서 compare_exchange_weak()에 대한 두 번째 인수는 유효하지 않습니다. 그러나 compare_exchange_weak()이 실행될 때 "head_! = old_head"를 감지하므로 절대 사용되지 않습니다. 그렇습니다. compare_exchange_weak()에 대한 잘못된 인수를 읽지 만 절대 사용되지 않습니다. 문제가 무엇입니까? 분명히 해줄 수 있니? – Alex

+0

@alex 왜 그들이 평등하지 않다고 생각합니까? 매달린 포인터를 따라 가면 값은 * anything *이 될 수 있습니다. 그리고'head _! = old_head_'는 어디에서 확인합니까? 나는 그것을 놓쳤는가? – Yakk

+0

아마도 나는 뭔가를 놓치고 있지만, 나는 정확히 무엇을 정확하게 이해할 수 없습니다. "head _! = old_head_"가 compare_exchange_weak() 안에 있는지 확인하십시오. 이 두 값이 같지 않으면 compare_exchange_weak()의 ​​두 번째 인수가 사용되지 않습니다. compare_exchange_weak()는 메모리에서 head의 현재 값을 원자 적으로 읽는 것으로 이해합니다. 첫 번째 스레드가 깨어 난 후에 논의 된 시나리오에서 레지스터의 헤드 값은 메모리의 헤드의 현재 값과 같지 않습니다. 그래서 compare_exchange_weak()은 그것을보고 2 번째 인수 (쓰레기, 우리가 레지스터에있는 머리의 잘못된 값 다음에 읽는)를 사용하지 않을 것입니다. – Alex

관련 문제