Abdullah Saleem
Abdullah Saleem

Reputation: 3811

Best way to terminate a thread

I'm working on a downloader which downloads multiple files simultaneously. Each download has its own Form which runs the downloading code in a thread. I'm looking for the best approach to terminate the running download threads for two reasons

So far there are three approaches

  1. Use a check variable like bool terminate
  2. Use Thread.Abort()
  3. Run the thread is a AppDomain and unload the AppDomain to terminate

Problem with the first approach is that threads keeps running until it hits the if statement. Even if the MainForm is closed the process keeps on running until all the downloading threads are terminated.

I don't know much about Thread.Abort but it is highly discouraged.

Here is the code for the last approach:

public class Processor : MarshalByRefObject
{
    private AsyncOperation _operation;

    private AppDomain Domain { get; set; }

    public delegate void ProgressChangedEventHnadler(Processor sender, int progress);

    public delegate void ProcessedEventHandler(Processor sender, EventArgs e);

    public delegate void ExceptionOccuredEventHandler(Processor sender, Exception ex);

    public event ProgressChangedEventHnadler ProgressChanged;

    public event ProcessedEventHandler Processed;

    public event ExceptionOccuredEventHandler ExceptionOccured;

    private void OnProgressChanged(int progress)
    {
        if(ProgressChanged!=null)
            ProgressChanged.Invoke(this,progress);
    }

    private void OnProcessed(EventArgs e)
    {
        if (Processed != null)
            Processed.Invoke(this, e);
    }

    private void OnExceptionOccured(Exception ex)
    {
        if (ExceptionOccured != null)
            ExceptionOccured.Invoke(this,ex);
    }

    public Processor()
    {
        _operation = AsyncOperationManager.CreateOperation(null);
    }

    public static Processor CreateInstance()
    {
        var locaion = Assembly.GetEntryAssembly().Location;
        var domain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
        var instance =(Processor)domain.CreateInstanceFromAndUnwrap(locaion, typeof (Processor).FullName);
        instance.Domain = domain;
        return instance;
    }

    public void Start()
    {
        var mainThread = new Thread(Process);
        mainThread.Start();
    }

    public void Stop()
    {
        AppDomain.Unload(Domain);
    }

    private void Process()
    {
        //Do the Work and raise events like 
        //_operation.Post(e => OnProcessed((EventArgs)e), EventArgs.Empty);
    }
}

Upvotes: 0

Views: 2727

Answers (1)

BartoszKP
BartoszKP

Reputation: 35911

In general you have two options:

  • allow the thread to terminate itself. This covers your first option.

  • terminate the thread externally. This covers your other options.

And that's it. And none of them, in general, can prevent the threads from running for indefinite time after they should (from the programmer's intent point of view) terminate.

The most predictable approach is the first one. If terminating takes too long, try to do the processing in smaller steps to allow checking the termination flag more frequently. Also, note the IsBackground flag which will help with the application being unable to close itself.

The whole problem with the other options is that any code (except for some special cases like finally blocks) can be just interrupted in the middle of its execution, which can lead to some undesired results (e.g. some unmanaged resources not released) - as it is explained in Thread.Abort documentation.

Note that the third approach in the newest versions of .NET framework is equivalent to calling the Abort method on your executing threads, as explained in the documentation:

The threads in domain are terminated using the Abort method, which throws a ThreadAbortException in the thread. Although the thread should terminate promptly, it can continue executing for an unpredictable amount of time in a finally clause.

So it seems better to use Thread.Abort from these two, as it's simpler and more readable.

If the first approach is problematic, and if you are well aware of the type of operations your thread is executing and there is no problem in interrupting them in-between then the "brutal" approach should be fine.

Upvotes: 2

Related Questions