“非阻塞”数据结构如何可能?

时间:2012-05-30 07:32:04

标签: multithreading algorithm data-structures language-agnostic nonblocking

我无法理解任何数据结构如何“非阻塞”。

假设您正在制作“非阻塞”哈希表。在某些时候,你的哈希表太满了,所以你必须重新哈希到一个更大的表中。

这意味着您需要分配内存,这是一种全局资源。因此,似乎您必须获取某种锁以防止堆的全局损坏...无论您的数据结构本身可能出现什么问题!
但那意味着在分配内存时,每个其他线程都必须阻塞...

我在这里想念的是什么? (如何)你可以在不阻塞正在做同样的另一个线程的情况下分配内存吗?

4 个答案:

答案 0 :(得分:3)

非阻塞设计的两个示例是optimistic designTransactional Memory

这个想法是 - 在大多数情况下,阻塞是多余的 - 因为两个OP可以同时发生而不会相互中断。但是,有时当两个OP同时发生并且数据因此而损坏时 - 您可以回滚到之前的状态,然后重试。

这些设计中可能仍然存在锁定,但数据被锁定的时间明显更短,并且仅限于发生OP影响的关键时间。

答案 1 :(得分:2)

仅针对某些定义,其他信息以及区分非阻止无锁等待条款,我建议阅读以下文章(我不会在这里复制相关段落,因为它太长了):

Definitions of Non-blocking, Lock-free and Wait-free

答案 2 :(得分:2)

大多数策略都有一个共同的基本模式。他们在循环中使用compare and swap (CAS)操作,直到成功为止。

例如,让我们考虑使用链表实现的堆栈。我选择了一个链表实现,因为很容易与CAS并发,但还有其他方法可以实现。我将使用类似C的伪代码。

Push(T item)
{
  Node node = new Node(); // allocate node memory
  Node initial;
  do
  {
    initial = head;
    node.Value = item;
    node.Next = initial;
  }
  while (CompareAndSwap(head, node, initial) != initial);
}

Pop()
{
  Node node;
  Node initial;
  do
  {
    initial = head;
    node = initial.Next;
  }
  while (CompareAndSwap(head, node, initial) != initial);
  T value = initial.Value;
  delete initial; // deallocate node memory
  return value;
}

在上面的代码中,CompareAndSwap是一个非阻塞的原子操作,它用一个新值替换内存地址中的值并返回旧值。如果旧值与预期值不匹配,则旋转循环并再次尝试。

答案 3 :(得分:0)

所有non-blocking意味着你永远不会无限期地等待,而不是你永远不会等待。只要您的堆也使用非阻塞算法实现,您可以在其上实现其他非阻塞算法。