macu 0 Newbie Poster

For the purpose of long running tasks in an ASP.NET application I've written some test code that I plan to use to fire off long tasks in another thread so that the web request can return. This is my first real world usage of multi-threading so I'm interested in any comments on my approach and the locking I've used in the following code. In my test code I've split this into two classes, firstly AsyncThreadAbstractTask:

public abstract class AsyncThreadAbstractTask
{
    protected delegate void TaskCompleteHandler();

    private TaskCompleteHandler _callback;

    private Boolean _started = false;
    private Object _lock = new Object();

    protected Boolean BeginTask(TaskCompleteHandler callback)
    {
        Boolean start = false;
        lock (_lock)
        {
            start = !_started;
            _started = true;
        }

        if (start)
        {
            _callback = callback;
            Thread thread = new Thread(ThreadRunTask);
            thread.Start();
        }

        return start;
    }

    protected void EndTask()
    {
        _callback = null;
        _started = false;
    }

    private void ThreadRunTask()
    {
        RunTaskCore();
        if (_callback != null) _callback();
    }

    protected abstract void RunTaskCore();
}

This begins the task and ensures that two threads can't start the same task (from the same created object which will be stored in Session). Other mechanisms (locking at db level) will stop two separately created objects running the same task.

An example of an inheriting class is AsyncDBTask:

public sealed class AsyncDBTask : AsyncThreadAbstractTask
{
    private Boolean _complete = false;

    public Boolean Complete
    {
        get { return _complete; }
    }

    public Boolean StartTask()
    {
        _complete = false;
        return base.BeginTask(this.TaskComplete);
    }

    protected override void RunTaskCore()
    {
        DBTask task = new DBTask();
        task.DoUpdate("whatever");
    }

    private void TaskComplete()
    {
        base.EndTask();
        _complete = true;
    }
}

UI code can start the task, and monitor progress by checking the Complete property. The actual task in the example is just delegated to another class DBTask which does some updates and inserts.

Any comments appreciated.