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

Advertisements

Step one

Hi everyone

I feel like starting with a good ol’ rant: developers suck!.Computer Voodoo

Ok, this mays sound harsh, but for the record, that includes me. We suck because we write buggy and unmaintainable code. And whenever we overcome those issues, someone will modify the code at a later date and ultimately will render it buggy and unmaintainable! And of course, that someone may be ourselves in the first place.

So what are the causes of this Great Curse?

They are numerous, but ultimately most of them relate to complexity:

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it? (B.Kernighan)

So, in our daily IT related actions, we need to relentlessly focus on simplicity. A lot of work has already been done around design rules, coding rules, frameworks and framework usages, documentation processes. I will refer to significant progress and effort along the way, but my main intention for this blog is to focus around what is usually called multi threading or parallelism. I certainly feel that simplicity if nowhere on the horizon for parallel programming, while our typical 2011 CPU has at least 4 cores.

My first multithreaded development experience dates from the mid 90’s, when I was working on custom three tiers application dedicated to check processing. For the past 6 years, I have been more intensively active on this topic, as I have been working on electronic trading systems for an investment bank. I did

  • design multi threaded architecture systems
  • code part of them
  • test them
  • instrument them
  • design a event driven multi core aware framework that has been implemented in numerous systems (IA+ Threading)
  • hold training sessions and conferences around the subject

My languages of choice are C++ and .Net and I have a significant experience around the Windows kernel.

My next post will be focused on multi threaded related assumptions.