Hungarian notation and thread safety

Joel Spolsky had a very good Making Wrong Code Look Wrong article where he rehabilitates the hungarian notation for certain dedicated purposes (tips: no, hungarian is not about junking your code with variable prefix such as string, int and array). Joel Spolsky presents the idea of prefixing unsafe (i.e. user provided) strings in the context of web-based application with us, standing for unsafe string. Such practice makes a lot of sense in situations where things have to be right by design (security is a typical example because no security holes are going to pop-up against typical non-hostile users).

Thread safety (TS) issues

Beside security, thread safety, for multithreaded applications, is another area that has to be right by design otherwise you are going to hit Heisenbugs. In .Net/C#, the most simple way to deal with thread safety is to rely on lock statements (some people would object that locking is unsafe by design and that transactions/agents/whatever should be used instead, that might be true but this is certainly beyond the scope of this post). Actually, I have found that designing multithreaded applications is not that hard but it requires some strong methodology to avoid things to get wrong by design.

TS level 1 : dedicated locks

A very common beginner mistake at multithreading to re-use some random object to ensure the locking scheme, worst of all, using the this statement.

public class Bar  
{  
  public void FooThreadSafe()  
  {  
    lock(this) { } // bravo, you just shoot your feet  
  }  
}  

Although, it may looks like a 12bytes overhead, a lock requires a dedicated object field in the class.

public class Bar  
{
  private object fooLock = new Lock();  
  public void FooThreadSafe()  
  {  
    lock(fooLock) { } // much better  
  }  
}  

The majar advantage of the dedicated lock instance approach is documentation. The purpose of dedicated object documentation is to explain which objects should be protected and when (Intellisense-like IDE feature makes this approach even more practical). A secondary advantage is encapsulation. The library end-user (i.e. the intern next door) is not aware of the “dedicated lock instance” stuff and might re-use whatever lockYXZ variable available for his own dark purposes. Don’t offer him the chance to do that, mark the field as private.

TS level 2 : hungarian locks

Beside unprotected (concurrent) accesses, the second most important issue in multithreaded applications is deadlocks. Against deadlocks, there is only one known solution (to my knowledge) : complete and permanent ordering of the locks. In other words, locks should always be taken in same order. You might think, “Ok, let’s just add a line in the dedicated lock object documentation to specify that.” Well, I have tried, it just does not work. Because, over time, your application evolves, the intern next-door don’t care about your documentation, new locks are added to fit some other requirements and the initial complete ordering is no more (although it should, but developpers are just so-not-failproof humans). The problem with those deadlocks is that you have no way to detect them just by looking at a piece of code. You have to look at the whole application code to ensure consistency. Here comes the hungarian rescue : the hungarian dedicated lock naming convention.

The locks should be taken in the order specified by the hungarian prefixes.

Let’s look at a small example, if you have two dedicated lock instances called lock1Bar and lock2Foo (lockX being the hungarian prefix), then you know that lock1Bar should be taken before lock2Foo. Any exception to this rule is a guaranteed-or-reimbursed deadlock. Additionally, refactoring tools make it so easy to rename all your variables as many time as you need that there is really no practical obstacle to implement such policy.


Reader Comments (1)

Yeah! I’m the first to post a comment on Joannes' blog! Besides this first useless statement of mine, it’s great to witness the birth of the blog of someone you know. Of course I would have more much enjoyed C++/metaprogramming in your “Software Engineering” first entry and I was not surprised to see C#/multithreaded code issues instead. But I am still really looking forward to the next entries! January 17, 2006 | Patrick