Thanh Nguyen
Thanh Nguyen

Reputation: 83

How to abort thread when current job in thread complete c#

I want when i click thread.Abort() and thread finish print label after that it will abort. It only abort thread when finish current job. Thanks

namespace ThreadTest
{
public partial class Form1 : Form
{
    Thread thread;
    bool loop = true;
    Stopwatch regularSW = new Stopwatch();
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        thread = new Thread(new ThreadStart(() => threadtest()));
        thread.Start();
    }
    private void button2_Click(object sender, EventArgs e)
    {
        thread.Abort();
    }
    public void threadtest()
    {
        while (loop)
        {
            regularSW.Start();
            Thread.Sleep(5000);
            regularSW.Stop();
            this.Invoke(new Action(() => label1.Text += "Sleep in: " + regularSW.Elapsed + Environment.NewLine));
        }
    }
}

}

Upvotes: 2

Views: 70

Answers (2)

Paul Turner
Paul Turner

Reputation: 39615

Aborting a thread is not something you should need to do in most applications; when the thread no longer has work to do, it will stop as a natural part of its lifecycle.

To allow this to happen, your code needs to signal that the method should stop executing. In .NET, the type CancellationTokenSource is used to allow thread-safe signalling that an operation should be stopped.

However, the most prominent concern is that your thread spends most of its time sleeping. This means that when the Cancel button is pressed, you must wait for the thread to wake up before it will notice that cancellation has been requested.

We can use the cancellation mechanism to simulate the thread sleeping by having it wait for a period of time, or for cancellation to be requested - whichever happens first:

Thread thread;
CancellationTokenSource cts;
Stopwatch regularSW = new Stopwatch();
public Form1()
{
    InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
    cts = new CancellationTokenSource();
    thread = new Thread(new ThreadStart(() => threadtest(cts.Token)));
    thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
    cts.Cancel();
}
public void threadtest(CancellationToken cancellation)
{
    while (!cancellation.IsCancellationRequested)
    {
        regularSW.Start();

        // Simulate a Thread.Sleep; returns true if cancellation requested.
        if (!cancellation.WaitHandle.WaitOne(5000))
        {
            regularSW.Stop();
            this.Invoke(() => label1.Text += "Sleep in: "
                + regularSW.Elapsed
                + Environment.NewLine);
        }
    }
}

Upvotes: 2

vcsjones
vcsjones

Reputation: 141588

Thread.Abort is a request, the operating system and thread are free to ignore it in situations where an abort is not possible. Generally, Abort should never be used in "by design" scenarios. Instead, your loop should check to see if there is a cancel action pending, perhaps something like this:

Thread thread;
bool loop = true;
volatile bool _cancelPending = false;
Stopwatch regularSW = new Stopwatch();
//Snip... unchanged code removed for brevity. 
private void button2_Click(object sender, EventArgs e)
{
    _cancelPending = true;
}
public void threadtest()
{
    while (loop)
    {
        if (_cancelPending) break;
        regularSW.Start();
        Thread.Sleep(5000);
        regularSW.Stop();
        this.Invoke(new Action(() => label1.Text += "Sleep in: " + regularSW.Elapsed + Environment.NewLine));
    }
}

Perhaps that is the purpose of your loop field, but I introduced another field, _cancelPending, in-case it is serving a different purpose.

Upvotes: 5

Related Questions