Stop Saying "Lock Free Solution"

I am writing this at the airport, just coming back from the Intel IDF event. I keep hearing that we have "Lock Free" solutions for all sorts of problems. I think that this is a really bad choice of words. Let me try to explain why:

My story starts with a friend who bought a sports car. That was a really good car with A very noisy engine. A new car like that is very expensive so he just got an old one. It worked fine but then one day as we drive to a party the car just stopped. We all went out popped the hood to look at the engine. Lovely engine. Shiny but it's not running. We didn't want to be late so eventually we found the solution. We all went to the back of the car and started pushing. I admit that it wasn't going that fast but we got to the party. Later we found out that the car was out of gas. Two weeks later we went to see a movie and then again the car suddenly stopped working. Now we check the meter and it looks like the car has enough gas. So again we pop the hood and look at the engine. Eventually we find a solution. We all get behind the car and start pushing. We had a few problems up the hill so we went around it. Later we found out that this time it was the electrical system. The third time the car stopped working I told my friend that we need to find a "Push-Free" solution. I just thought that a "Push Free" solution would be more efficient. So now when we have car trouble we try to actually fix it... and we stopped calling it a Push Free solution. Now we just call it a fix.

Sure, it is faster and simpler to just start pushing the car instead of really understanding the problem, and you know what, pushing the car can go around almost any problem that you may have.

Locks can work around almost any problem that you may have. Just do me a favor and don't call it a solution.

When you solve a problem in your application don't call it a "Lock-Free" solution... Let's call it a solution.

** the friend in the story is as fictional as the need to use locks outside an infrastructure mechanism.

Here is more: Locks Are Bad

Here is me at the IDF event:

Asaf

For more complete information about compiler optimizations, see our Optimization Notice.

Top

>>From what I am hearing from you guys, maybe we should explain lock engines but there should be a clear definition of where and when we use them, just as we do with global variables. How does that sound?

Sounds right to me, Asaf. I like your analogy with global variables.

Hey Guys, great meeting you both on IDF. Reading the comment I did in fact think about goto-s. Goto-s can also be a good tool but they implicate a bad software design, as would locks. I can think of several examples where you would use workarounds only because you try to avoid the use of goto-s. A simple example is stopping a loop from within a nested loop. Using ‘break’ would not work and so you need to use a dedicated flag or return from the function. I would argue that locks are too low level and implicate a bad software design unless used really carefully. It does sound like a good idea to teach locks and goto-s as part of architecture or any other advanced class, but most times you wouldn't teach goto-s as the foundation of programming, and my opinion is that you should do the same with locks.
The majority of programmers write application level code. I do use locks, as you said Dick, in device drivers as infrastructures. The thing with drivers is that they have very good and thought-out design and very delicate programming. Most times application developers hope for the best assuming that an exception would save them if there was a bug. We still can't really solve things like race conditions under a lock (see my post "Locks Are Bad") and the only way to prevent a deadlock is by verifying the order in which locks are used, which means that locks must be defined in the system design which makes locks redundant at most times because going to the drawing board you can probably find a better solution than locks.
From what I am hearing from you guys, maybe we should explain lock engines but there should be a clear definition of where and when we use them, just as we do with global variables. How does that sound?
I still argue that we shouldn’t call all the solutions in the world “the rest of the world which is not locks”…

Asaf, it was a great pleasure to meet you at IDF. Thanks for your blog. Your last words clarify something I didn't understand when we chatted about locks last week -- I now realize that you are avoiding explicitly programming with locks, vs. implementing higher-level services (such as a thread-safe queue) with an internal locking mechanism of some kind. I'm all for that, and encourage my students to avoid programming with explicit locks from the first day we talk about such issues.

I still want my students to know about the existence of locks: so they can understand their shortcomings such as low-level thinking and lack of scalability; so they can understand spin-locks, etc., in OS source code when we get around to reading that; so they can understand what they read (e.g., what it means for Java and Python have a global interpreter lock). But I agree with you that I want them to solve high-level programming problems with high-level tools, which can be implemented to manage low-level resources well.

Sometimes we can push analogies too far, just like cars.

This situation reminds me of John Gustafson asserting that we should never teach recursion in CS courses because recursion is death to high performance computing. He's right, just as you are that overuse of locks can affect performance. Its just that seeking performance is the law, it is not always the number one design issue. I am a pragmatist. We have tools in the computer geek toolkit. It was goal is writing maintainable code that runs fast enough now and in the foreseeable future, than everything is fair game.

I was about to say that avoidance of locks is not as severe an issue as avoiding gotos, and that I would never teach their use, but I actually do. I teach use of branch instructions in my architecture class; they are a key concept well worth appropriately using.

Hi Clay. In my car analogy I was comparing Locks to pushing the car, so if you are using a different kind of lock I would say that maybe it means pushing the car with a lawnmower instead of have people push it. To your example, what I am looking for is a solution that does not require locking at all. If you have a good infrastructure solution such as Queue it is possible not to use locks at all. The Queue may use locks internally but this is alright because I argue that it is OK to use kernel synchronization objects in our infrastructure. The Lock-Free replacements that you mentioned use the same design as regular locks and thus must be not the right answer. How does that sound?

I don't mind the term "lock-free" since these solutions are not using the mutex object provided by the threading library being used. However, I find it a bit misleading since rather than that heavy lock object, the algorithms use some other form of synchronization, like an atomic test-and-set or compare-and-swap operation on a variable. To use your car analogy, it would be like taking your firend's nice shiny engine out, replacing it with a lawnmower engine, and calling the car "engine-free".