是否可以创建没有锁的线程安全集合?

时间:2010-06-03 14:52:04

标签: algorithm multithreading language-agnostic

这仅仅是针对利益问题,欢迎提出任何问题。

那么可以创建没有任何锁的线程安全集合吗?通过锁我的意思是任何线程同步机制,包括Mutex,Semaphore,甚至Interlocked,所有这些机制。是否可以在用户级别,而无需调用系统功能?好的,可能实施效果不好,我对理论上的可能性很感兴趣。如果不是最低限度的手段是什么?

编辑:为什么不可变集合不起作用。

此类Stack,方法Add,返回另一个堆栈。

现在这是程序:

Stack stack = new ...;

ThreadedMethod()
{
   loop
   {
      //Do the loop
      stack = stack.Add(element);
   }
}

此表达式stack = stack.Add(element)不是原子的,您可以从其他线程覆盖新堆栈。

谢谢, 安德烈

6 个答案:

答案 0 :(得分:12)

即使是大师软件开发人员也似乎对构成锁的内容存在误解。

必须区分原子操作和锁。比较和交换等原子操作执行操作(否则需要两条或更多条指令)作为单个不间断指令。锁是从原子操作构建的,但是它们可能导致线程忙等待或睡眠,直到锁被解锁。

在大多数情况下,如果您设法使用原子操作实现并行算法而不诉诸锁定,您会发现它会快几个数量级。这就是为什么对无等待和无锁算法非常感兴趣的原因。

在实施各种无等待数据结构方面已经进行了大量研究。虽然代码往往很短,但由于出现了微妙的竞争条件,很难证明它们真的有用。调试也是一场噩梦。然而,已经做了很多工作,你可以找到无等待/无锁的哈希映射,队列(迈克尔斯科特的无锁队列),堆栈,列表,树,列表继续。如果你很幸运,你也会发现一些开源实现。

只需谷歌'锁定我的数据结构',看看你得到了什么。

有关这个有趣主题的进一步阅读,请从Maurice Herlihy的The Art of Multiprocessor Programming开始。

答案 1 :(得分:5)

是的,不变的收藏品! :)

答案 2 :(得分:3)

是的,可以在没有系统支持的情况下进行并发。您可以使用Peterson's algorithm或更一般的bakery algorithm来模拟锁定。

答案 3 :(得分:3)

这实际上取决于你如何定义术语(正如其他评论者所讨论的那样),但是,至少,许多数据结构可能以非阻塞的方式实现(没有使用传统的互斥锁。)

如果您对该主题感兴趣,我强烈建议您阅读the blog of Cliff Click - Cliff是Azul Systems的首席大师,他生产硬件+自定义JVM以大规模运行Java系统并行(想想大约1000个核心和数百GB的RAM区域),显然在这些类型的系统中锁定可能是死亡(免责声明:不是Azul的员工或客户,只是他们工作的崇拜者)。 / p>

Click博士提出了一个非阻塞的HashTable,它基本上是一个使用原子CompareAndSwap操作的复杂(但相当精彩)的状态机。

有一篇由两部分组成的博客文章描述了算法(part onepart two)以及在Google上发表的演讲(slidesvideo) - 后者特别是一个很棒的介绍。花了我一些去“得到它” - 这很复杂,让我们面对它吧! - 但如果你预先确定(或者如果你比我更聪明!)你会发现它非常有益。

答案 4 :(得分:2)

我不这么认为。 问题在于,在某些时候,您将需要一些互斥原语(可能在机器级别),例如原子测试和设置操作。否则,你总是可以设定一个竞争条件。一旦你有一个测试和设置,你基本上有一个锁。

话虽如此,在指令集中没有任何支持的旧硬件中,您可以禁用中断,从而防止另一个“进程”接管但有效地不断地将系统置于序列化模式并强制排序相互排斥一段时间。

答案 5 :(得分:1)

至少你需要原子操作。单个cpu有无锁算法。我不确定多个CPU的