Я произвел простую реализацию безблокирующей (lockfree) очереди, используя новый std::atomic
в C ++ 11. Я не понимаю, что я здесь делаю не так.
#include <atomic>
template<typename T>
class lockless_queue
{
public:
template<typename DataType>
struct node
{
node(const DataType& data)
: data(data), next(nullptr) {}
DataType data;
node* next;
};
lockless_queue()
: head_(nullptr) {}
void produce(const T &data)
{
node<T>* new_node = new node<T>(data);
// put the current value of head into new_node->next
new_node->next = head_.load(std::memory_order_relaxed);
// now make new_node the new head, but if the head
// is no longer what's stored in new_node->next
// (some other thread must have inserted a node just now)
// then put that new head into new_node->next and try again
while(!std::atomic_compare_exchange_weak_explicit(
&head_,
&new_node->next,
new_node,
std::memory_order_release,
std::memory_order_relaxed)) {}
}
node<T>* consume_all()
{
// Reset queue and return head atomically
return head_.exchange(nullptr, std::memory_order_consume);
}
private:
std::atomic<node<T>*> head_;
};
// main.cpp
#include <iostream>
int main()
{
lockless_queue<int> s;
s.produce(1);
s.produce(2);
s.produce(3);
auto head = s.consume_all();
while (head)
{
auto tmp = head->next;
std::cout << tmp->data << std::endl;
delete head;
head = tmp;
}
}
И мой вывод:
2
1
Segmentation fault (core dumped)
Можно мне несколько указателей, где искать, или указание на то, что я делаю неправильно?
Благодарность!
2 ответа
Вы разыменовываете tmp
вместо head
:
while (head)
{
auto tmp = head->next;
std::cout << tmp->data << std::endl;
delete head;
head = tmp;
}
Должно быть:
while (head)
{
std::cout << head->data << std::endl;
auto tmp = head->next;
delete head;
head = tmp;
}
Вот почему 3
не появляется в вашем выводе, а Segmentation fault
появляется.
У вас есть еще одна ошибка в вашем коде, которая не появится, пока вы не начнете пытаться выполнять параллельные постановки в очередь. Если ваш compare_exchange_weak_explicit
выходит из строя, это означает, что другому потоку удалось изменить указатель head
, и поэтому, прежде чем вы сможете снова попробовать свой CAS, вам необходимо повторно загрузить новое значение head
указатель на ваш new_node->next
. Следующее поможет:
while(!std::atomic_compare_exchange_weak_explicit(
&head_,
&new_node->next,
new_node,
std::memory_order_release,
std::memory_order_relaxed)) {
new_node->next = head_.load(std::memory_order_relaxed);
}
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .