0

I am new to winforms programming and I am starting to work with threads.

I have managed to start a thread, but now I want to be able to click on a cancel button to stop the thread.

Here is my code so far...

This starts the thread:

private void btnSessions_Click(object sender, EventArgs e)
{
    Thread downloadThread = new Thread(new ThreadStart(DownloadThread));
    downloadThread.Start();
}

This is the thread:

void DownloadThread()
{
     // Do the work
}

This is the button I want to use to cancel the thread:

private void btnCancel_Click(object sender, EventArgs e)
{
     // Stop the thread
}

Can anyone help me work out what I need to put in btnCancel_Click please?

rene
  • 41,474
  • 78
  • 114
  • 152
Trevor Daniel
  • 3,785
  • 12
  • 53
  • 89

3 Answers3

3

You should use the Task Parallel Library (TPL) for this, which supports a natural way of canceling tasks:

private CancellationTokenSource _tokenSource2;
private CancellationToken _token;

private void btnSessions_Click(object sender, EventArgs e)
{
    _tokenSource2 = new CancellationTokenSource();
    _token = _tokenSource2.Token;

    Task task = Task.Run(() => DownloadThread(), _token);
}

private void DownloadThread()
{
    while (true)
    {
        //do work

        //cancel if needed
        if (_token.IsCancellationRequested)
        {
            _token.ThrowIfCancellationRequested();
        }
    }
}

private void btnCancel_Click(object sender, EventArgs e)
{
    // Stop the thread
    _tokenSource2.Cancel();
}

More about canceling tasks: http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

Why you should not use Thread.Abort: What's wrong with using Thread.Abort()

Community
  • 1
  • 1
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • sorry if I am being stupid but its saying "The name 'tokenSource2' does not exist in the current context" - I cannot work out where I should put the var tokenSource2 = new CancellationTokenSource(); in the code :( – Trevor Daniel Nov 12 '13 at 13:36
  • 1
    @TrevorDaniel I've updated my answer. If you can't grasp the concepts of field declaration and variable scopes, you should probably go through some basic C# (or any other language) tutorials, before trying to write multi-threaded applications. – dcastro Nov 12 '13 at 13:46
  • You can use a `CancellationToken` even with an explicit `Thread`, you don't *need* to use it with a `Task`. Also, there's no point in checking if cancellation is requested before calling `ThrowIfCancellationRequested`. The *point* of `ThrowIfCancellationRequested` is that it only throws if cancellation is requested, and it does nothing otherwise. `IsCancellationRequested` exists so that you can do something *other than throwing an exception* if cancellation is requested. – Servy Jan 07 '14 at 20:39
2

You need to make the downloadThread a field in your object:

Thread downloadThread; 
private void btnSessions_Click(object sender, EventArgs e)
{
     downloadThread = new Thread(new ThreadStart(DownloadThread));
     downloadThread.Start();
}

void DownloadThread()
{
     // Do the work
}

private void btnCancel_Click(object sender, EventArgs e)
{
     downloadThread.Abort();
}

A background worker would be a better solution for ui related processing.

Peter
  • 27,590
  • 8
  • 64
  • 84
  • [Thread.Abort Method](http://msdn.microsoft.com/en-us/library/ty8d3wta%28v=vs.110%29.aspx) is evil: it is not determined where the thread execution will be terminated. So, the **resources** acquired by the thread **might not be disposed**. Please avoid calling `Thread.Abort()` method. – Sergey Vyacheslavovich Brunov Nov 12 '13 at 18:15
0

It's better don't use Thread and especially Thread.Abort for task like this. C# has high abstract wrapper to hide threads. Just use Task and CancellationToken. Here is example:

var cts = new CancellationTokenSource(); // define in class
CancellationToken ct = cts.Token;

private void btnSessions_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() => DownloadThread(), ct ); // start task
}

private void DownloadThread()
{
    // You need to check this at some point where cancel may occur
    if (ct.IsCancellationRequested)
        ct.ThrowIfCancellationRequested();
}

private void btnCancel_Click(object sender, EventArgs e)
{
    cancelToken.Cancel(false); // cancel task
}

More information can be found at msdn

Eugene
  • 1,699
  • 1
  • 12
  • 13