В книге Энтони Уильямса «Параллелизм в C ++ в действии», в разделе 7.2.1, перечислена реализация стека без блокировки:
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) Я не понимаю, почему может произойти такой сценарий и почему следующая функция pop () вызовет состояние гонки:
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) Почему для нескольких потоков, вызывающих pop () одновременно, переменная old_head может указывать на один и тот же объект узла после строки (3)?
head_!=old_head_
? Я пропустил это? 29.03.2017old_head
, а неold_head_
? 30.03.2017