Jul 08

If you know how much pain it is to debug / unit test multi threaded code, you likely don’t want to do it again.

The biggest problem is that you can’t be sure if it would work if it was single threaded, so that there are solely bugs introduced by concurrently accesses.

You could of cause alter all affected parts by hand to run on a single thread, just to verify that there are indeed no other logic bugs. But as it would be time consuming and sometimes not practical at all as there is just too much involved, you shouldn’t do that.

Therefore I’d advice you to use a single point where you deal with all threading stuff, some kind of action executor.

A interface could look like this:

public interface IActionExecutor
{
    void Execute(Action action, Action callBack, Action<Exception> errorHandle);
    void Execute(Action action, Action callBack);
    void Execute(Action action, Action callBack, bool executeCallBackInMainThread);
    void Execute(Action action);
    void Execute(Action action, bool executeInMainThread);
}

For production purpose, the multi threaded implementation could be as simple as this:

public class MultiThreadedActionExecutor : IActionExecutor
{
    #region IActionExecutor Members

    public void Execute(Action action, Action callBack, Action<Exception> errorHandle)
    {
        new Thread(() =>
                       {
                           try
                           {
                               action();
                               SyncContext.Current.Post(x =< callBack(), null);
                           }
                           catch (Exception ex)
                           {
                               errorHandle(ex);
                           }
                       }).Start();
    }

    public void Execute(Action action, Action callBack)
    {
        Execute(action, callBack, false);

    }

    public void Execute(Action action)
    {
        Execute(action, false);
    }

    public void Execute(Action action, Action callBack, bool executeCallBackInMainThread)
    {
        new Thread(() =<
        {
            try
            {
                action();
                if (executeCallBackInMainThread)
                {
                    SyncContext.Current.Post(x =< callBack(), null);
                }
                else
                {
                    callBack();
                }

            }
            catch(Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }).Start();
    }

    public void Execute(Action action, bool executeInMainThread)
    {
        new Thread(() =<
                       {
                           try
                           {
                               if (executeInMainThread)
                               {
                                   SyncContext.Current.Post(x =< action(), null);
                               }
                               else
                               {
                                   action();
                               }
                           }
                           catch (Exception)
                           {
#if DEBUG
                               throw;
#endif
                           }
                       }).Start();
    }

    #endregion
}

The SyncContext just contains the SynchronizationContext of the main thread, this is my implementation:

public class SyncContext
{
    private static SynchronizationContext _current;

    public static SynchronizationContext Current
    {
        get { return _current; }
    }

    public static void Initialize()
    {
        if (_current == null)
        {
            _current = SynchronizationContext.Current;
        }
    }
}

And for unit testing or debugging, you can use this single threaded implementation

public class SingleThreadedActionExecutor
{
    public void Execute(Action action, Action callBack, Action<Exception> errorHandle)
    {
        try
        {
            action();
            callBack();
        }
        catch (Exception ex)
        {
            errorHandle(ex);
        }
    }

    public void Execute(Action action, Action callBack)
    {
        Execute(action, callBack, false);
    }

    public void Execute(Action action)
    {
        Execute(action, false);
    }

    public void Execute(Action action, Action callBack, bool executeCallBackInMainThread)
    {
        try
        {
            action();

            callBack();
        }

        catch (Exception)
        {
#if DEBUG
            throw;
#endif
        }
    }

    public void Execute(Action action, bool executeInMainThread)
    {
        try
        {
            action();
        }
        catch (Exception)
        {
#if DEBUG
            throw;
#endif
        }
    }
}

Although you should use a dependency injection tool like StructureMap, you could also use a static variable exposing the current IActionExecuter, in both cases you would only have to change one line of code to turn all multi threaded actions to single threaded ones and vice versa.

Another benefit would be, you don’t have to do the tedious invoking when working with WindowsForms. If you are using the MVP pattern, this will be a great time saver.

Tagged with:
preload preload preload