Reputation: 3811
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
bool terminate
Thread.Abort()
AppDomain
and unload the AppDomain
to terminateProblem 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
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 aThreadAbortException
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