는 잠금이없는 스택 구현이 나열됩니다이 자물쇠가없는 스택 클래스의 '삭제'노드가 경쟁 조건을 유발하는 이유는 무엇입니까? 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) 뒤에 동일한 노드 객체를 가리킬 수 있습니까?
죄송합니다. 아직 명확하지 않습니다. 예, 스레드 1은 현존하지 않는 포인터를 따라가고 다른 변수에 이미 할당 된 "다음"에 값을 읽습니다. 따라서 compare_exchange_weak()에 대한 두 번째 인수는 유효하지 않습니다. 그러나 compare_exchange_weak()이 실행될 때 "head_! = old_head"를 감지하므로 절대 사용되지 않습니다. 그렇습니다. compare_exchange_weak()에 대한 잘못된 인수를 읽지 만 절대 사용되지 않습니다. 문제가 무엇입니까? 분명히 해줄 수 있니? – Alex
@alex 왜 그들이 평등하지 않다고 생각합니까? 매달린 포인터를 따라 가면 값은 * anything *이 될 수 있습니다. 그리고'head _! = old_head_'는 어디에서 확인합니까? 나는 그것을 놓쳤는가? – Yakk
아마도 나는 뭔가를 놓치고 있지만, 나는 정확히 무엇을 정확하게 이해할 수 없습니다. "head _! = old_head_"가 compare_exchange_weak() 안에 있는지 확인하십시오. 이 두 값이 같지 않으면 compare_exchange_weak()의 두 번째 인수가 사용되지 않습니다. compare_exchange_weak()는 메모리에서 head의 현재 값을 원자 적으로 읽는 것으로 이해합니다. 첫 번째 스레드가 깨어 난 후에 논의 된 시나리오에서 레지스터의 헤드 값은 메모리의 헤드의 현재 값과 같지 않습니다. 그래서 compare_exchange_weak()은 그것을보고 2 번째 인수 (쓰레기, 우리가 레지스터에있는 머리의 잘못된 값 다음에 읽는)를 사용하지 않을 것입니다. – Alex