Короткая версия:
Я пытаюсь заменить std :: atomic из C ++ 11, используемый в реализации без блокировки, для одного производителя, для очереди с одним потребителем из здесь .Как заменить это на boost::atomic
?
Длинная версия:
Я пытаюсь повысить производительность нашего приложенияс рабочими нитями.Каждый поток имеет свою очередь задач.Мы должны синхронизироваться с помощью блокировки перед удалением / постановкой в очередь каждой задачи.
Тогда я нашел статью Херба Саттера о очереди без блокировки.Это похоже на идеальную замену.Но в коде используется std::atomic
из C ++ 11, который я не мог представить в данный момент в проекте.
Более гуглирование привело к некоторым примерам, таким как этот для Linux (echelon's) и для Windows (TINESWARE's) .Оба используют специфические для платформы конструкции, такие как WinAPI InterlockedExchangePointer
и GCC __sync_lock_test_and_set
.
. Мне нужно только поддерживать Windows и Linux, так что, возможно, я смогу обойтись с некоторыми #ifdef
s.Но я подумал, что было бы лучше использовать то, что обеспечивает boost::atomic
.Boost Atomic еще не является частью официальной библиотеки Boost.Поэтому я скачал исходный код из http://www.chaoticmind.net/~hcb/projects/boost.atomic/ и использую включаемые файлы с моим проектом.
Это то, что я получаю до сих пор:
#pragma once
#include <boost/atomic.hpp>
template <typename T>
class LockFreeQueue
{
private:
struct Node
{
Node(T val) : value(val), next(NULL) { }
T value;
Node* next;
};
Node* first; // for producer only
boost::atomic<Node*> divider; // shared
boost::atomic<Node*> last; // shared
public:
LockFreeQueue()
{
first = new Node(T());
divider = first;
last= first;
}
~LockFreeQueue()
{
while(first != NULL) // release the list
{
Node* tmp = first;
first = tmp->next;
delete tmp;
}
}
void Produce(const T& t)
{
last.load()->next = new Node(t); // add the new item
last = last.load()->next;
while(first != divider) // trim unused nodes
{
Node* tmp = first;
first = first->next;
delete tmp;
}
}
bool Consume(T& result)
{
if(divider != last) // if queue is nonempty
{
result = divider.load()->next->value; // C: copy it back
divider = divider.load()->next;
return true; // and report success
}
return false; // else report empty
}
};
Некоторые изменения, на которые следует обратить внимание:
boost::atomic<Node*> divider; // shared
boost::atomic<Node*> last; // shared
и
last.load()->next = new Node(t); // add the new item
last = last.load()->next;
и
result = divider.load()->next->value; // C: copy it back
divider = divider.load()->next;
Применяю ли я load () (и неявное хранилище ()) от boost :: atomic правильноВот?Можем ли мы сказать, что это эквивалентно исходной безблокировочной очереди C ++ 11 Саттера?
PS.Я изучил многие потоки в SO, но ни один из них не дает пример для очереди boost :: atomic & free-free.