Why locks suck?


I hate locks. Well, now that I have your undivided attention, I can speak the truth: I have a love and hate relationship with locks. Well, mostly hate actually.

And when I say locks, I mean Mutexes, CriticalSections, SlimLocks, ReadWriter, Monitor; all existing flavor of those.
Let’s examine them.

Pros:

  • their usage is relatively easy to grasp
  • almost every language offer them
  • they are the ubiquitous threading tool
  • every developer (is expected to) knows locks and threads

Cons:

  • they only implement exclusive access to code
  • they are immensely hard to master
  • they do not compose
  • they provide partial thread safety only
  • they impair performance

Let me elaborate:

1.They only implement exclusive access to code

This sucks bad time: acquiring a lock is an explicit call to a function/method you need to insert to your code. But in fact, you rely on the lock to protect a state, i.e. data, not code. It is lock usage 101: you have to make sure that you acquire the lock every time you have to access or change the associated state.

During my debugging sessions, I have often seen this error: someone changed the state without locking the state, leading to inscrutable race conditions.

Java and C# provide the synchronized keyword. But as is this just syntactic sugaryou still face the initial issue. It would be far better if you could declare a set of field(s) as being synchronized, letting the language (or CLR/JCM) handling the heavy lifting!

2. They are immensely hard to master

I have probably held more than one hundred technical interview so far and only a couple of candidates I have met gave me the impression they were comfortable with locks and threads. Of course they are hard, it is the all point of this blog to demonstrate this.

You have to follow some arcane rules to make sure you will not encounter an issue:

  • make sure you acquire the lock when you access the state (see above)
  • make sure you release the lock, even in case of exceptions
  • make sure you acquire locks in the proper order
  • check if your lock support recursion
  • take care of hidden locks (hidden in libraries, OSes)

You see a pattern there? You must always be very careful when you use lock. Because no tool will help you discover if you failed to respect those rules.

3. They do not compose

Deadly sin here. The ability to build software by composing  pre-existing and independent component is a must have nowadays!

But locks throw that away: if you plug some frameworks the wrong way, you risk having deadlocks, and no documentation will help you avoid this. Even worst, you can have a strong and healthy code base but see it fail badly after some framework upgrade.

You cannot put the blame on the framework authors: I have yet to see a satisfying format to document locks implementation and usage in a library.

Threads do not compose well either; most frameworks are ‘thread safe’ without offering first class support of threads (by being scalable for one). And the frameworks that expect and benefit from threads usually impose their threading model on you: they create their own thread and notify you, call your code within those.

4.They provide only partial thread safety

My concern here are frameworks and libraries that claim to be thread safe. Note that it can extended to all existing components, but it is more an issue for those two.

The catch is to understand what ‘safe’ means in thread safe. It turns out it can mean many things. Possible meanings:

  1. Language primitive type instances will not be corrupted in multi threaded usage. It is really the weakest safety you can provide. It basically means that no low level exception will occur due to race conditions as an example. You may be surprised, but it is exactly the level you get with System.MulticasDelegates in C#.
  2. Framework objects state will not be corrupted in multi threaded usage. It is the one you usually get.
  3. You can configure some threading attributes of the library/framework. This one is usually offered by middlewares (MOM, Databases). The accessible settings are often limited to the size of a pool of threads.
  4. You will not encounter deadlocks in multi threaded usage, whatever  threading model you choose. This one is complex to achieve except for the most trivial libraries
  5. You can control the threading model for the framework. This is the one you want as a developer, but this is one you never gets.

Bottom line

Locks are the best tool most developer have to try and tame the multi threaded beast; but they still expose many pitfalls and shortcomings. A few years ago I came to the conclusion that YOU CANNOT FIX LOCKS, they will always fail, and it is impossible to brace yourself against it.

Thats where I decided there must some better alternatives, either being identified or to invent. But that will be the subject from another topic.

Key takeaway: Locks are no silver buller, except maybe to your own foot. Use with caution, exposure can lead to many bad things

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.