The main disadvantage of lock-free techniques is that you have to write code without any critical sections, that is, you have to properly manage arbitrary interleaving of actions. It's hard enough to manage staleness/inconsistency of data at high (business logic) level, never mind the low level where the code is not even executed in the written order.
Regarding sched_yield, another common (and, IMO, superior) approach to that issue is to drop the first lock and then acquire the second lock after the try-lock on it failed. Then you drop the second lock and retry the whole sequence again.
Comments
Not necessarily, but it is fine for this purpose I suppose. See https://news.ycombinator.com/item?id=21959692
Glad to see lock hierarchies mentioned. Barriers are new to me so that was nice.
IMO, it would be nice to at least have a mention of lock-free techniques and their advantages and disadvantages.
The main disadvantage of lock-free techniques is that you have to write code without any critical sections, that is, you have to properly manage arbitrary interleaving of actions. It's hard enough to manage staleness/inconsistency of data at high (business logic) level, never mind the low level where the code is not even executed in the written order.
Also lock free usually means atomics which means memory fences. Those can be slow. It's another tool you should have available though.
Memory fences and atomics are a part of lock-based code as well. They're just hidden by the locking and notification primitives.
Regarding sched_yield, another common (and, IMO, superior) approach to that issue is to drop the first lock and then acquire the second lock after the try-lock on it failed. Then you drop the second lock and retry the whole sequence again.
Agreed that sched_yield() is unlikely to be the right approach. A better approach is to use nanosleep() with an exponential backoff.