Lock free synchronization

断了今生、忘了曾经 提交于 2020-12-01 10:46:11

问题


My question is related to multithreading lock-free synchronization. I wanted to know the following:

  1. What are general approaches to achieve this? I read somewhere about LockFreePrimitives like CompareAndExchange (CAS) or DoubleCompareAndExchange (DCA) but no explanation for those were given? Any approaches to MINIMIZE use of locks?

  2. How does Java/.NET achieve their concurrent containers? Do they use locks or lock-free synch?

Thanks in advance.


回答1:


Here are some general approaches that can minimize the use of locks, assuming your algorithm has some particular exploitable features:

  1. When updating a single numeric variable, you can use non-blocking primitives such as CAS, atomic_increment, etc. They are usually much faster that a classic blocking critical section (lock, mutex).

  2. When a data structure is read by multiple threads, but only written by one or few threads, an obvious solution would be a read-write lock, instead of a full lock.

  3. Try to exploit fine grain locking. For example, instead of locking an entire data structure with a single lock, see if you can use multiple different locks to protect distinct sections of the data structure.

  4. If you're relying on the implicit memory fence effect of locks to ensure visibility of a single variable across threads, just use volatile1, if available.

  5. Sometimes, using a conditional variable (and associated lock) is too slow in practice. In this case, a volatile busy spin is much more efficient.

More good advice on this topic here: http://software.intel.com/en-us/articles/intel-guide-for-developing-multithreaded-applications/

A nice read in another SO question: Lock-free multi-threading is for real threading experts (don't be scared by the title).

And a recently discussed lock-free Java implementation of atomic_decrement: Starvation in non-blocking approaches


1 The use of volatile here applies to languages such as Java where volatile has defined semantics in the memory model, but not to C or C++ where volatile preceded the introduction of the cross-thread memory model and doesn't integrate with it. Similar constructs are available in those languages, such as the various std::memory_order specifiers in C++.




回答2:


There are some useful way to use lock-free sychronization (such as those @Tudor mentions). But I want to warn about one thing - lock-free syncrhonization doesn't compose.

You may have, for example, an integer maintained by compare&swap, and it's OK. You may also have a queue, maintained by a lock-free algorithms (it's a bit tricky, but there are good algorithms for it), and the queue is also OK.
But if you try to use the counter to count the elements in a queue, you'll get wrong answers. There will be times when an element was added, but the counter doesn't yet reflect it (or vice versa), and you can get bugs if you trust it (e.g. you may try to add to a full queue).

In short - you can have each element consistent with itself, but not consistent with each other.




回答3:


Compare and swap is useful, but there is an even simpler (so called 'lock-free') technique that is useful in certain producer/consumer use cases that might be useful so I will mention it.

Imagine you have a function doWork() that writes to a buffer.

  1. Thread A initializes a volatile boolean variable (flag) to false that is accessible by both Thread A and creates a volatile buffer object that doWork will output to Thread B (Global, etc).
  2. Thread A creates thread B, which calls doWork().
  3. Thread B's doWork() begins creating/writing to the buffer. When finished, it sets the boolean to true.
  4. Thread A can poll a global boolean flag that starts out false. When it turns true (non false), it can access the data in the buffer object, assured that is finished. Between polls Thread A can do other work. (So for example it polls once in an update call and does not wait for a true value). This doesn't take into account error handling, but this can also be handled within the buffer.

This only works because A only reads and B only writes, but this use case is fairly common for 'background worker' threads. This will only sure to work on Java or C# where volatile comes with the guarantees.



来源:https://stackoverflow.com/questions/9103758/lock-free-synchronization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!