Я работаю через Антони Уильямс Книга параллелизма для C++ 11.C++ 11 std :: atomic compare_exchange_weak и контейнер стека
Я немного смущен поп-реализацией стека, свободного от блокировки.
template<typename T>
class lock_free_stack
{
private:
struct node
{
std::shared_ptr<T> data;
node* next;
node(T const& data_): data(std::make_shared<T>(data_)){}
};
std::atomic<node*> head;
public:
void push(T const& data)
{
node* const new_node = new node(data);
new_node->next = head.load();
while(!head.compare_exchange_weak(new_node->next, new_node));
}
std::shared_ptr<T> pop()
{
node* old_head = head.load();
while(old_head && !head.compare_exchange_weak(old_head, old_head->next));
// Does This not return the data of the next node before the head if
// compare_exchange_weak returns true
return old_head ? old_head->data : std::shared_ptr<T>();
}
};
Линия, которая вызывает у меня путаницу, является двумя последними строками поп-функции.
while(old_head && !head.compare_exchange_weak(old_head, old_head->next));
return old_head ? old_head->data : std::shared_ptr<T>();
Будет ли функция compare_exchange_weak не меняет old_head к следующему узлу в стеке, если она возвращает истину? Это приведет к возврату, возвращающему данные из следующего узла, а не к старой голове в верхней части стека, когда old_head не является nullptr.
Я интерпретировал это неправильно?
Имеет ли этот образец проблему с ABA, а также потенциально считывает неопределенную память (old_head-> next)? –
@MikeVine предполагается, что задан главный узел. push был вызван до pop. Тогда идея pop будет возвращать верхний узел, я не вижу этого, когда это происходит, когда он меняет старую голову на следующий узел, когда compare_exchange_weak == true – MWright
Если это только один читатель, тогда это сработает. Если, однако, есть 2 читателя или более, то это терпит неудачу.Этот класс предназначен для использования только с одним считывателем? Если нет, я отправлю пример того, как это может произойти. –