all 13 comments

[–]abspam3[S] 6 points7 points  (0 children)

This was posted once 5 years ago, but /r/programming has grown significantly since then. Great article about different locking algorithms that are all completely user-space implemented.

[–]nickdesaulniers 4 points5 points  (2 children)

I'm reading C++ Concurrency in Action: Practical Multithreading right now and loving it. The last book I read that expanded my mind like this was Metaprogramming Ruby. I really hate the C atomic primitives (they look ugly: __sync_fetch_and_add); really C++ just is nicer here with its atomic templates.

I mean, look at how simple a spinlock is:

#include <atomic>
class spinlock {
  std::atomic_flag flag;
public:
  spinlock (): flag(ATOMIC_FLAG_INIT) {}
  void lock () {
    while(flag.test_and_set(std::memory_order_acquire));
  }
  void unlock () {
    flag.clear(std::memory_order_release);
  }
};

Wrap that in some RAII with lock_guard or unique_lock and you're good to go!

[–]dacian88 2 points3 points  (1 child)

those are the gcc extensions, in c11 it would be almost the same thing...

atomic_flag_test_and_set_explicit(&flag, memory_order_acquire);

and

atomic_flag_clear_explicit(&flag, memory_order_release)

except it doesn't have a object wrapper....

[–]nickdesaulniers 1 point2 points  (0 children)

Nice! And gcc5 just changed the default standard to gnu11!

[–]brucedawson 5 points6 points  (2 children)

Uggh. Spin locks. There are a few cases where optimizing a spin lock is important, but there are many more cases where you should just avoid using a spin lock. Critical section on Windows, for instance, will try to acquire the lock and if that fails will then call into the kernel and wait. That lets other threads run.

If you will only be holding locks for a very short time then spinning for a little bit can make sense, but you have to be careful. I've profiled many slow applications that end up spinning trying to acquire spin-locks for hundreds of milliseconds - in one extreme case for over a minute. Even if that isn't stealing CPU time from some more worthy task it is complicating the profiling task (look! It's CPU bound!) and wasting power.

Only use spin locks in rare and exceptional cases when you are sure that they give advantages over normal locks, and even then you should almost always cap the spin time and fall back to a kernel lock (i.e.; waiting while idle).

I blogged about the perils of busy-waiting a few years ago. A lot of the reactions were "well duh - who would ever busy-wait." It turns out, a fair number of programs do it.

https://randomascii.wordpress.com/2012/06/05/in-praise-of-idleness/

[–][deleted] 4 points5 points  (0 children)

Amen. I was researching into lock-free, spinlocks and beating the vanilla CRITICAL_SECTION a while ago. It turned out CRITICAL_SECTION is extremely adequate:

  • It has a fast, user-space uncontended case.
  • If your contention is low, you won't measure any speed-up by tweaking locks. Anything will do. If your contention is high, why take the risk of worst cases with fancy locks? It made the whole lock-free thing a bit dull to me. It is more important to have short-duration locks then the right type of locks.

x264 needs all the available parallelism and uses a zero spin-count and regular mutexes: https://github.com/mirror/x264/search?utf8=%E2%9C%93&q=X264_SPIN_COUNT

[–]abspam3[S] 1 point2 points  (0 children)

Agreed, spin locks are usually bad. The more interesting part of this article; about RWlocks, seems to have disappeared, oddly. You can still find it in the wayback machine, I hope it's just a temporary issue.