Sangeetha
Sangeetha

Reputation: 709

Abort long running thread in button click event

In my WPF application, I have a long running process which converts files to PDFs using BlueBeam Q Server. When the process takes place, it should not freeze, so the below code has written to take care of that:

private void btn_convert_Click(object sender, RoutedEventArgs e)
{
        thread = new Thread(new ThreadStart(WorkerMethod));
        thread.SetApartmentState(ApartmentState.STA);
        thread.IsBackground = true;
        thread.Name = "PDF";
        thread.Start();
}

WorkerMethod()
{
//code to connect to Q server and conversion goes here
}

Now, when the process starts, a cancel button will be visible to the user. When the user presses cancel, I want to abort the thread started. I wrote the code as below:

private void btn_cancel_Click(object sender, RoutedEventArgs e)
    {
        if (thread.Name == "PDF")
            thread.Abort(); 
    }

But the thread doesn't abort and continues the process. Please give me your valuable suggestions.

Upvotes: 1

Views: 2996

Answers (3)

Basti
Basti

Reputation: 1004

You could use the CancellationTokenSource as described here:
http://msdn.microsoft.com/en-us/library/dd997364.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

static void CancelWithThreadPoolMiniSnippet()
{

//Thread 1: The Requestor 
// Create the token source.
CancellationTokenSource cts = new CancellationTokenSource();

// Pass the token to the cancelable operation.
ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);

// Request cancellation by setting a flag on the token.
    cts.Cancel();
}

//Thread 2:The Listener 
static void DoSomeWork(object obj)
{
    CancellationToken token = (CancellationToken)obj;
    for (int i = 0; i < 100000; i++)
    {
        // Simulating work.
        Thread.SpinWait(5000000);

        if (token.IsCancellationRequested)
        {
            // Perform cleanup if necessary. 
            //... 
            // Terminate the operation. 
            break;
        }
    }
}

This post describes other possible ways:
Question about terminating a thread cleanly in .NET

Upvotes: 1

Thorsten Dittmar
Thorsten Dittmar

Reputation: 56697

You should avoid Abort whenever possible. Search SO for how to cancel threads gracefully - which can not be done when the thread code calls other code you can not influence, like a third party library method or something like that.

For example if your thread method does something like this:

WorkerMethod()
{
    CallFunctionInExternalDLL();
}

it can not be aborted properly.

To "cancel" such a thread, it's best to indicate to the thread it should cancel (using a bool flag, for example) and have the thread roll back its result (for example, delete a created PDF or things like that). Your application could then just continue as if the thread had never been started.

For example your code could then look like this:

WorkerMethod()
{
    CallFunctionInExternalDLL();
    if (m_threadAborted)
        RollBackWhatFunctionDid();
}

If your thread looks like this:

WorkerMethod()
{
    while (true)
    {
        CallFunctionInExternalDLL();
    }
}

You could do this:

WorkerMethod()
{
    while (!m_threadAborted)
    {
        CallFunctionInExternalDLL();
    }

    if (m_threadAborted)
        RollBackStuff();
}

In these examples, m_threadAborted is a bool flag declared like this:

private volatile bool m_threadAborted = false;

Upvotes: 4

Xaruth
Xaruth

Reputation: 4104

You can use Backgroundworker instead of Thread, and you will be able to cancel it if you code include a loop (you have to test a Boolean property in each loop)

// define the backgroundWorker
this.backgroundWorker.DoWork += new DoWorkEventHandler(this.BackgroundWorker_DoWork);
this.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);
this.backgroundWorker.WorkerSupportsCancellation = true;

// execute process
this.backgroundWorker.RunWorkerAsync();

// cancel process
this.backgroundWorker.CancelAsync();

and in your code of BackgroundWorker_DoWork :

// in a loop
if (this.backgroundWorker.CancellationPending == false)
{
...
}

Upvotes: 1

Related Questions