[英]Lock-Free Queue with boost::atomic - Am I doing this right?
精簡版:
我試圖從這里用於無鎖,單生成器,單消費者隊列實現中的C ++ 11替換std :: atomic。 如何用boost::atomic
替換它?
長版:
我正試圖通過工作線程從我們的應用程序中獲得更好的性能。 每個線程都有自己的任務隊列。 我們必須在出列/排隊每個任務之前使用鎖同步。
然后我找到了Herb Sutter關於無鎖隊列的文章。 這似乎是一個理想的替代品。 但是代碼使用了C ++ 11中的std::atomic
,我現在無法將其引入到項目中。
更多的谷歌搜索導致了一些例子,例如這個用於Linux (echelon的) , 這個用於Windows(TINESWARE的) 。 兩者都使用平台的特定構造,如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;
我是否正確地在boost :: atomic中應用了load()(以及隱式store())? 我們可以說這相當於Sutter原來的C ++ 11無鎖隊列嗎?
PS。 我研究了SO上的許多線程,但似乎都沒有為boost :: atomic&lock-free隊列提供示例。
你有沒有試過英特爾螺紋構建模塊' atomic<T>
? 跨平台和免費。
也...
單個生產者/單個消費者使您的問題更容易,因為您的線性化點可以是單個操作員。 如果您准備接受有界隊列,它會變得更容易。
有界隊列提供緩存性能的優勢,因為您可以保留緩存對齊的內存塊以最大化您的命中,例如:
#include <vector>
#include "tbb/atomic.h"
#include "tbb/cache_aligned_allocator.h"
template< typename T >
class SingleProdcuerSingleConsumerBoundedQueue {
typedef vector<T, cache_aligned_allocator<T> > queue_type;
public:
BoundedQueue(int capacity):
queue(queue_type()) {
head = 0;
tail = 0;
queue.reserve(capacity);
}
size_t capacity() {
return queue.capacity();
}
bool try_pop(T& result) {
if(tail - head == 0)
return false;
else {
result = queue[head % queue.capacity()];
head.fetch_and_increment(); //linearization point
return(true);
}
}
bool try_push(const T& source) {
if(tail - head == queue.capacity())
return(false);
else {
queue[tail % queue.capacity()] = source;
tail.fetch_and_increment(); //linearization point
return(true);
}
}
~BoundedQueue() {}
private:
queue_type queue;
atomic<int> head;
atomic<int> tail;
};
查看文檔中的boost.atomic ringbuffer示例 :
#include <boost/atomic.hpp>
template <typename T, size_t Size>
class ringbuffer
{
public:
ringbuffer() : head_(0), tail_(0) {}
bool push(const T & value)
{
size_t head = head_.load(boost::memory_order_relaxed);
size_t next_head = next(head);
if (next_head == tail_.load(boost::memory_order_acquire))
return false;
ring_[head] = value;
head_.store(next_head, boost::memory_order_release);
return true;
}
bool pop(T & value)
{
size_t tail = tail_.load(boost::memory_order_relaxed);
if (tail == head_.load(boost::memory_order_acquire))
return false;
value = ring_[tail];
tail_.store(next(tail), boost::memory_order_release);
return true;
}
private:
size_t next(size_t current)
{
return (current + 1) % Size;
}
T ring_[Size];
boost::atomic<size_t> head_, tail_;
};
// How to use
int main()
{
ringbuffer<int, 32> r;
// try to insert an element
if (r.push(42)) { /* succeeded */ }
else { /* buffer full */ }
// try to retrieve an element
int value;
if (r.pop(value)) { /* succeeded */ }
else { /* buffer empty */ }
}
代碼的唯一限制是必須在編譯時知道緩沖區長度(或者在構造時,如果用std::vector<T>
替換數組)。 據我所知,允許緩沖區增長和縮小並非易事。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.