作者说,实施的in this article的MPMC队列不是无锁的,并且阻塞了生产者/消费者队列。
根据分类,基于阵列的MPMC失败了 溢出,不需要GC,没有优先级,因果FIFO,阻塞 生产者和消费者排队。算法非常简单 快速。它在官方意义上并非无锁定,只是通过实施 没有互斥体的原子RMW操作方法。
但根据这个(http://www.1024cores.net/home/lock-free-algorithms/introduction):
锁定自由 锁定自由意味着整个系统向前发展 无论如何。每个线程的前进进度是 不保证(也就是说,个别线程可能会饿死)。
无锁算法的一个例子是:
void stack_push(stack * s, node * n) {
node * head;
do {
head = s - > head;
n - > next = head;
}
while (!atomic_compare_exchange(s - > head, head, n));
}
可以看出,一个线程可以"旋转"在理论上在循环中 无限地。但循环的每次重复都意味着其他一些线程 已经取得了进展(也就是说,成功地将节点推送到了 堆)。阻塞/中断/终止线程无法阻止 其他线程的进展。因此,整个系统 毫无疑问会取得进展。
似乎上面的MPMC队列在无锁中满足这些假设。但为什么说它在官方意义上不是无锁的,让我感到困惑。想知道我是否想念这里的东西?
不熟悉c ++,the c# port version here是阻塞算法,也不是无锁?
文章中的代码引用于此处:
template<typename T>
class mpmc_bounded_queue
{
public:
mpmc_bounded_queue(size_t buffer_size)
: buffer_(new cell_t [buffer_size])
, buffer_mask_(buffer_size - 1)
{
assert((buffer_size >= 2) &&
((buffer_size & (buffer_size - 1)) == 0));
for (size_t i = 0; i != buffer_size; i += 1)
buffer_[i].sequence_.store(i, std::memory_order_relaxed);
enqueue_pos_.store(0, std::memory_order_relaxed);
dequeue_pos_.store(0, std::memory_order_relaxed);
}
~mpmc_bounded_queue()
{
delete [] buffer_;
}
bool enqueue(T const& data)
{
cell_t* cell;
size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
for (;;)
{
cell = &buffer_[pos & buffer_mask_];
size_t seq =
cell->sequence_.load(std::memory_order_acquire);
intptr_t dif = (intptr_t)seq - (intptr_t)pos;
if (dif == 0)
{
if (enqueue_pos_.compare_exchange_weak
(pos, pos + 1, std::memory_order_relaxed))
break;
}
else if (dif < 0)
return false;
else
pos = enqueue_pos_.load(std::memory_order_relaxed);
}
cell->data_ = data;
cell->sequence_.store(pos + 1, std::memory_order_release);
return true;
}
bool dequeue(T& data)
{
cell_t* cell;
size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
for (;;)
{
cell = &buffer_[pos & buffer_mask_];
size_t seq =
cell->sequence_.load(std::memory_order_acquire);
intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
if (dif == 0)
{
if (dequeue_pos_.compare_exchange_weak
(pos, pos + 1, std::memory_order_relaxed))
break;
}
else if (dif < 0)
return false;
else
pos = dequeue_pos_.load(std::memory_order_relaxed);
}
data = cell->data_;
cell->sequence_.store
(pos + buffer_mask_ + 1, std::memory_order_release);
return true;
}
private:
struct cell_t
{
std::atomic<size_t> sequence_;
T data_;
};
static size_t const cacheline_size = 64;
typedef char cacheline_pad_t [cacheline_size];
cacheline_pad_t pad0_;
cell_t* const buffer_;
size_t const buffer_mask_;
cacheline_pad_t pad1_;
std::atomic<size_t> enqueue_pos_;
cacheline_pad_t pad2_;
std::atomic<size_t> dequeue_pos_;
cacheline_pad_t pad3_;
mpmc_bounded_queue(mpmc_bounded_queue const&);
void operator = (mpmc_bounded_queue const&);
};