Tuesday, September 30, 2008

Unhandled Exception Processing In The CLR

In this article published in MSDN September, the author categorized 3 situations where an exception would occur in the CLR and what would happen if not catched in the CLR.

  1. Exceptions in managed code
  2. Exceptions in unmanaged c++ coded which is invoked via P/Invoke in managed code
  3. Exceptions in managed code which is called via CLR Hosting API or COM Interop in native code

For situation 1 and 2, when a managed exception is not catched, the exception is swallowed by the CLR, if it happens in a thread created using System.Threading.Thread class, in the Finalizer thread or in the CLR thread pool threads. Otherwise, UnhandledException event is raised as part of the CLR's unhandled exception processing, which terminates the process. We can register an event handler to log about the failure for later diagnosis.

For situation 3, if an exception is thrown in a thread created in the CLR, in the .NET Framework 1.0 and 1.1, the CLR swallows the exception, while in the .NET Framework 2.0 and later, the CLR lets it go unhandled after triggering its unhandled exception process. On the other hand, if that exception is thrown on the thread created outside the CLR, the exception is wrapped as SEH Exception, and propagated backed to the native code.

Managed exceptions, if rethrown or packaged as inner exceptions as the following, the CLR would reset the starting point of the exception. The implication is that you may observe the point of failure is changed to that line in your log.

try
{
     ...
}
catch(FileNotFoundException e)
{
     ...
     throw e;    //or throw new ApplicationException(e);
}

Finally, if an exception occurs in a different AppDomain, this exception would be marshalled-by-value back and thrown in the calling AppDomain.

Further readings:

Monday, September 15, 2008

9 Reusable Parallel Data Structures and Algorithms

As I mentioned before, cpu development has moved into a multi-core stage. To fully utilize the computing power in the chip, concurrency programming is the key. This MSDN article introduced 9 parallel data structures and algorithms which allow one to design a multi-threaded program in a very intuitive way. The best part of this article I found is the author explained why the source code executes correctly and which parts of the code, if changed, could result into a deadlock.

  1. Countdown Latch - This class allows a program to wait for a counter to reach zero. It uses Interlocked.Decrement to substract the counter and EventWaitHandle to coordinate to wait and signal events.
  2. Reusable Spin Wait - Sometimes putting a program to sleep can be expensive due to the cost, i.e., context switch, involved. For a short period of time, i.e., cycles, spin wait is a good choice. This structure instructs a cpu to wait based on the number of processors in a computer. If there is only one cpu, the structure puts the program to sleep. If there is more than one cpu, the structure instructs the cpu to spin.
  3. Barriers - Say, task1 and task2 can be executed in parallel, but task3 can not proceed until both task1 and task2 are completed. One way to code this is to run task2 in thread2 and execute task1 in thread1. After task1 complete, call Join in thread2 to wait for the completion of task2. Or we can use Barriers to wait for something to complete before proceed to the next step.
  4. Blocking Queue - Very straightforward and easy to understand. It's also a good example of how to use Monitor.Pulse / Monitor.Wait in a correct way.
  5. Bounded Buffer - This is a data structure to solve consumer/ producer problem. The class is implemented similar to Block Queue.
  6. Thin Event - Win32 events can be expensive to allocate. This class uses the SpinWait structure to wait first and, if an event is still not signaled, it allocates a Win32 Event to wait on. Lazy evalation is the design philosophy behind this class.
  7. Lock-Free LIFO Stack - You don't have to lock an entire stack to push or pop an item. The author showed that an Interlocked.CompareExchange operation is enough to ensure push or pop operations thread-safe in a stack.
  8. Loop Tiling - If you know what parallel query is, you know what loop tiling is doing. It's easier to show you the codes than describe them in words.

    List<T> list = ...;
    foreach(T e in list) { S; }

    A C# for loop above can be run in parallel using the function below.

    Parallel.ForAll(list, delegate(T e) { S; }, Environment.ProcessorCount);
  9. Parallel Reductions - Some operations, such as, max, min, count, sum, can be performed in parallel. The author provided a Reduce function to simplify the task. The function reminded me of the MapReduce method.