锁定自由同步

时间:2012-02-01 21:40:00

标签: multithreading synchronization locking lock-free

我的问题与多线程无锁同步有关。我想知道以下内容:

  1. 实现这一目标的一般方法是什么?我在某处读过有关LockFreePrimitives的内容,比如CompareAndExchange(CAS)或DoubleCompareAndExchange(DCA),但没有给出解释? MINIMIZE使用锁的任何方法?

  2. Java / .NET如何实现其并发容器?他们使用锁或无锁同步吗?

  3. 提前致谢。

3 个答案:

答案 0 :(得分:6)

假设您的算法具有一些特定的可利用功能,以下是一些可以最小化锁定使用的一般方法:

  1. 更新单个数字变量时,可以使用非阻塞原语,例如CAS,atomic_increment等。它们通常比经典的阻塞关键部分(lock,mutex)快得多。

    < / LI>
  2. 当一个数据结构由多个线程读取,但只由一个或几个线程写入时,一个明显的解决方案是读写锁,而不是完全锁定。

  3. 尝试利用细粒锁定。例如,不是使用单个锁锁定整个数据结构,而是查看是否可以使用多个不同的锁来保护数据结构的不同部分。

  4. 如果您依赖锁的隐式内存栅栏效应来确保跨线程可见单个变量,只需使用volatile 1 (如果可用)。 p>

  5. 有时,在实践中使用条件变量(和相关的锁定)太慢。在这种情况下,volatile忙碌旋转效率更高。

  6. 此处有关此主题的更多好建议:http://software.intel.com/en-us/articles/intel-guide-for-developing-multithreaded-applications/

    另一个SO问题的好读:Lock-free multi-threading is for real threading experts(不要被标题吓到)。

    最近讨论过的atomic_decrement的无锁Java实现:Starvation in non-blocking approaches


    1 此处volatile的使用适用于Java等语言,其中volatile已在内存模型中定义了语义,但未在C {C ++中定义{{1}在引入跨线程内存模型之前,并没有与它集成。这些语言中提供了类似的结构,例如C ++中的各种std::memory_order说明符。

答案 1 :(得分:1)

有一些有用的方法可以使用无锁同步(例如@Tudor提到的那些)。但是我想警告一件事 - 无锁同步化并不构成。

例如,您可能有一个由compare&amp; swap维护的整数,并且没关系。您可能还有一个由无锁算法维护的队列(这有点棘手,但它有很好的算法),队列也可以。
但是如果你试图使用计数器来计算队列中的元素,你会得到错误的答案。有时会添加一个元素,但计数器还没有反映它(反之亦然),如果你信任它就可以得到bug(例如你可能会尝试添加到一个完整的队列)。

简而言之 - 您可以让每个元素与自身保持一致,但彼此不一致。

答案 2 :(得分:0)

比较和交换是有用的,但有一种更简单(所谓的'无锁')技术,在某些可能有用的生产者/消费者用例中很有用,所以我会提到它。

想象一下,你有一个写入缓冲区的函数doWork()。

  1. 线程A将一个易失性布尔变量(flag)初始化为false,可由线程A访问,并创建一个易失性缓冲区对象,doWork将输出到线程B(全局等)。
  2. 线程A创建线程B,调用doWork()。
  3. 线程B的doWork()开始创建/写入缓冲区。完成后,它将布尔值设置为true。
  4. 线程A可以轮询开始为false的全局布尔标志。当它变为真(非假)时,它可以访问缓冲区对象中的数据,确保完成。在民意调查之间,线程A可以做其他工作。 (例如,它在更新调用中轮询一次并且不等待真值)。这不会考虑错误处理,但也可以在缓冲区内处理。
  5. 这只能起作用,因为A只读取而B只写入,但这种用例对于“后台工作者”线程来说相当常见。这只能肯定适用于Java或C#,其中volatile带有保证。