Thursday, May 31, 2012

Critical Blocks and Improper Lock Objects

The blog is moving to a new domain. This post has found a new home: http://www.patrickdelancy.com/2012/05/critical-blocks-and-improper-lock-objects/

Quick catch-up... critical application blocks are blocks of code that can only be executed by one thread at a time. Stock example for illustration:
public static class SmackTracker {
    private static int smackCount = 0;
    private static object locker = new object();

    public static void HitItAgain() {
        lock (locker) {
            smackCount++;
        }
    }
}
No matter how many threads call this method, the smackCount will only be incremented by one thread at a time, but this is not a post on the value and usage of thread locking...

What I want to cover is some common pitfalls people get into, sometimes without even realizing it. The resulting issues can sometimes manifest as phantom performance issues, inconsistent data corruption, intermittent memory exceptions and any number of other vague or elusive symptoms, like clammy hands.

Don't become a victim! When using sync objects, follow these simple rules...

  1. Don't use publicly accessible sync objects.
  2. Avoid using strings as lock objects.

Don't use publicly accessible sync objects.

The short explanation here is this... if the sync object is publicly accessible, it can be used (incorrectly or accidentally) for locking an external code block, resulting in potential deadlocks or other issues.

Historically it was common, even recommended, to use "this" or "typeof(MyType)" as your lock object. This is no longer recommended. Consider this example:
//Don't use public sync objects, and "this" is public!

using System;
using System.Threading;

namespace FacepalmCoding
{
    public class Program
    {
        public static void Main(string[] args)
        {
            DateTime start = DateTime.Now;
            
            Console.WriteLine("Starting worker threads...");
            
            Person theMan = new Person("The Man");
            
            Thread p2thread = new Thread(new ThreadStart(theMan.Operate));
            
            p2thread.Start();
            Thread.Sleep(10);
            
            lock (theMan) {
                theMan.OperateNoLock();
            }
            
            p2thread.Join();
            
            Console.WriteLine("This should have taken about 3 seconds in parallel, instead it took {0} seconds.", (DateTime.Now - start).TotalSeconds);            

            Console.WriteLine("Done.");
        }
    }
    
    public class Person {
        private readonly string personId;

        public Person(string id) {
            personId = id;
        }
        
        public void Operate() {
            DateTime start = DateTime.Now;
            
            //use private instance string as sync object for this resource
            lock (this) {
                // ... do stuff that takes 3 seconds ...
                Thread.Sleep(3000);
            }

            Console.WriteLine("Person '{0}' operation took {1} seconds to complete.", personId, (DateTime.Now - start).TotalSeconds);
        }
        
        public void OperateNoLock() {
            DateTime start = DateTime.Now;
            
            // ... do stuff that takes 3 seconds ...
            Thread.Sleep(3000);

            Console.WriteLine("Person '{0}' operation took {1} seconds to complete (No Lock).", personId, (DateTime.Now - start).TotalSeconds);
        }
    }
}
Starting worker thread...
Person 'The Man' operation took 3.0108053 seconds to complete.
Person 'The Man' operation took 3.0108053 seconds to complete (No Lock).
This should have taken about 3 seconds in parallel, instead it took 6.0216106 seconds.
Done.
Click here to see it in action.

Note in this example, "theMan" is the same object reference as "this" internally. The result... an internal critical code block is locked in an external scope. This is bad!

Avoid using strings as lock objects.

In .NET and Java (and probably others), strings are public sync objects. The lock is identified by the string value, instead of the string object reference. This means that any string value (doesn't have to be string literal) can be used to as a sync key globally throughout the entire process, as if you were referencing a global object, no matter the scope of the string variable you are using. That may be hard to follow... here is an example...
//Do not use strings as thread lock/sync objects!

using System;
using System.Threading;

namespace FacepalmCoding
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Starting worker threads...");
            
            Person firstPerson = new Person("first");
            Person secondPerson = new Person("second");
            Role firstRole = new Role("first");
            
            Thread p1thread = new Thread(new ThreadStart(firstPerson.Operate));
            Thread p2thread = new Thread(new ThreadStart(secondPerson.Operate));
            Thread r1thread = new Thread(new ThreadStart(firstRole.Operate));
            
            p1thread.Start();
            p2thread.Start();
            r1thread.Start();
            
            p1thread.Join();
            p2thread.Join();
            r1thread.Join();
            
            Console.WriteLine("Done.");
        }
    }
    
    public class Person {
        private readonly string personLocker = "lock object";
        private readonly string personId;

        public Person(string id) {
            personId = id;
            //personLocker = id;
        }
        
        public void Operate() {
            DateTime start = DateTime.Now;
            
            //use private instance string as sync object for this resource
            lock (personLocker) {
                // ... do stuff that takes 3 seconds ...
                Thread.Sleep(3000);
            }
            
            Console.WriteLine("Person '{0}' operation took {1} seconds to complete.", personId, (DateTime.Now - start).TotalSeconds);
        }
    }

    public class Role {
        private readonly string roleLocker = "lock object";
        private readonly string roleId;

        public Role(string id) {
            roleId = id;
            //roleLocker = id;
        }

        public void Operate() {
            DateTime start = DateTime.Now;
            
            //use different private string as sync object here
            //but since the string value is the same, will wait 
            //for "personLocker" to be released!
            lock (roleLocker) {
                // ... do stuff that takes 3 seconds ...
                Thread.Sleep(3000);
            }
            
            Console.WriteLine("Role '{0}' operation took {1} seconds to complete.", roleId, (DateTime.Now - start).TotalSeconds);
        }
    }
}

Starting worker threads...
Person 'first' operation took 3.0108053 seconds to complete.
Person 'second' operation took 6.0216106 seconds to complete.
Role 'first' operation took 9.0324159 seconds to complete.
Done.
Click here to see it in action.

Un-comment lines 40 and 62 and watch how the behavior changes.

Closing Thoughts

In case you forgot why any of this matters, I'll summarize it in a bullet list:
  • Deadlocks and race conditions can be extremely difficult to diagnose and troubleshoot.
  • Improper use of critical application blocks can cause deadlocks and race conditions.
  • Widely-scoped sync objects can be accidentally abused.
  • 'this', 'typeof' and any string value are all public sync objects.

Wednesday, May 23, 2012

Order of Operations in nested try..catch..finally

The blog is moving to a new domain. This post has found a new home: http://www.patrickdelancy.com/2012/05/order-of-operations-in-nested-try-catch-finally/

Let's dive in and take a look at some common and not-so-common exception handling arrangements.

Everyone should be familiar with the standard try..catch..finally construct:
try {
    //this code will run only until an exception is thrown
}
catch {
    //this code will run only IF and exception is thrown
}
finally {
    //this code will run always AFTER the try and/or catch blocks have been executed
}
Here is a less common arrangement. When might this be appropriate to use?
try {
    try {
    }
    catch {
    }
}
finally {
}
Now let's look at some concrete examples. Consider this code snippet:
string output = "";
try {
    output += "A";
    try {
        throw new InvalidOperationException("1");
        output += "B";
    }
    finally {
        output += "C";
    }
    output += "D";
}
catch (Exception e) {
    output += e.Message;
}
finally {
    output += "E";
}
Console.WriteLine("Output: " + output);
Output: AC1E
There are two interesting points to note here: 1) the exception is raised to the outer try..catch. It is not suppressed by the nested try..finally, and 2) the nested finally block executes before the outer catch!

Now consider this code snippet:
string output = "";
try {
    output += "A";
    try {
        throw new InvalidOperationException("1");
        output += "B";
    }
    finally {
        throw new InvalidOperationException("2");
        output += "C";
    }
    output += "D";
}
catch (Exception e) {
    output += e.Message;
}
finally {
    output += "E";
}
Console.WriteLine("Output: " + output);
Output: A2E
Like the first example, the exception is raised to the outer try..catch, but the difference here is that the first exception is suppressed! Only exception "2" is captured! The short answer is do not throw exceptions from a catch or finally.

Wednesday, May 16, 2012

Exceptional Introduction

The blog is moving to a new domain. This post has found a new home: http://www.patrickdelancy.com/2012/05/exceptional-introduction/

There has been a lot of discussion over the years about when and how to use exception throwing and handling. The general consensus seems to shift every once in a while. The performance of exceptions is not the primary purpose of this article, but I felt the need to discuss it in order to truly address the role of exceptions in software troubleshooting.

Exceptions are Expensive, like Store Brand is Cheap

Maybe the best way to breach the topic of exception performance is to simply give you a short list of axioms that I believe to be true.

1. Exceptions are expensive

It has been proven many times that there is additional cost associated with constructing and throwing an exception. This seems to be exaggerated in managed applications (.NET, Java, etc.). That being said, this extra "cost" of constructing and throwing an exception would only be noticeable in time-critical real-time systems, or if they are used excessively. That brings me to my next axiom...

2. Exceptions should be just that... exceptions to normal operation

I firmly believe that when an application is running properly, there should ideally be no exceptions thrown... ever.

Don't start writing your flame comments yet! Notice the emphasized words in that statement. I completely understand that this situation is difficult if not impossible. We live in a corrupted world, and there is no such thing as a perfect developer, let alone a perfect application or system.

Building on this perception of errors, if you are returning success messages in an error or exception context, stop it! I recently worked on a system where an API call returned this message: <error code="$0000">Error: Completed successfully</error>

There are absolutely great reasons to write exceptions into your application... that brings us to my third axiom...

3. Exceptions can be used effectively to increase system stability and code maintainability

No, this is not a contradiction of my previous statements. Maybe the best way for me to tackle this section is to just give you a bullet list.

Good times to raise exceptions:
  • Invalid parameters
    • When validating input parameters to a function, constructing an exception can provide a lot of valuable information to help troubleshoot the problem. Possibly even informing the user so that they can correct the inputs and re-submit.
  • Enforce code assumptions
    • If you are building a library (for internal or external use), you should first of all document any assumptions you make about the objects coming from your factories or the objects you are acting upon. When it is feasible, test these assumptions and throw an exception so you can trace the source of the problem.
  • External resources are unreachable or behave in an unexpected way
    • This could be a database, 3rd party library, web service, etc.
  • etc. 
Bad times to raise exceptions:
  • To return valid values to a calling function
    • Use return values instead!
  • On a timer, as a status update
    • Code smells (indicator you are using this anti-pattern): You have a custom exception type called "StatusReport"
    • Raise an event instead!
  • etc.
Exceptions have been designed to capture details about errant behavior in an application. They contain a lot of valuable information that can help to troubleshoot everything from programming errors to network instability. That was a lot of background and build-up to get to the main point of this article...

Exceptions contain valuable information. Don't ignore them!

Following from my three axioms above, if an exception is raised, don't ignore it! An empty catch block is a common code smell. This particular code smell usually enters the code when you are working on something else, and an exception is preventing you from reaching the code you care about at that moment. So you slap in an empty catch to suppress the exception and get to your other code. This is like sticking a piece of gum on a leaky pipe and walking away.

"But what about expected errors in a 3rd party library?" Okay... so you are using a library that was written more poorly than your own code, and it raises an exception that can be safely ignored. What happens when that library gets updated, and that "safe to ignore" exception doesn't fire anymore, but a similar exception could be thrown which CANNOT be safely ignored? Now you are suppressing a valid exception that could result in bad behavior within your own application! In the very least, you should have some tracing or logging message that is generated when the exception occurs. I plan to address this more in an upcoming article about application logging and tracing. For now, we will leave it at that.