In this code, when button1
is clicked twice, it creates 2 separate threads. On one click, it creates a new thread on the heap and field t1
points to the new thread on the heap. When I click button2
, it aborts the last thread (which t1
refers to).
How do I abort the other thread?
Thread t1;
ThreadStart ts1;
private void button1_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(myfunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
t1.Abort();
}
One method is for a thread to call interrupt on the target thread. The target thread should periodically call Thread. interrupted and if it returns true terminate gracefully. Another approach is to use a volatile boolean flag which a thread sets to true to terminate and the target thread checks the flag periodically.
If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur. If Abort is called on a thread that has not been started, the thread will abort when Start is called. If Abort is called on a thread that is blocked or is sleeping, the thread is interrupted and then aborted.
Use thread. Interrupt(); instead of Abort() method.
By using thr. Abort(); statement, we can terminate the execution of the thread.
Well, the OO answer would be to hold a list of threads as a field.
private readonly List<Thread> threads = new List<Thread>();
And to then add the newly constructed thread to the list in the first handler.
var thread = new Thread(myfunc);
thread.Start();
threads.Add(thread);
Then you could iterate through each thread in the second handler, aborting each of them in turn.
foreach(var thread in threads)
thread.Abort();
But I think the most important point here is that there is almost never a good reason to call Thread.Abort
.
From the MSDN page:
When a thread calls Abort on itself, the effect is similar to throwing an exception; the ThreadAbortException happens immediately, and the result is predictable. However, if one thread calls Abort on another thread, the abort interrupts whatever code is running. There is also a chance that a static constructor could be aborted. In rare cases, this might prevent instances of that class from being created in that application domain. In the .NET Framework versions 1.0 and 1.1, there is a chance the thread could abort while a finally block is running, in which case the finally block is aborted.
The thread that calls Abort might block if the thread that is being aborted is in a protected region of code, such as a catch block, finally block, or constrained execution region. If the thread that calls Abort holds a lock that the aborted thread requires, a deadlock can occur.
You would be much better off using some form of signalling, such as setting a ManualResetEvent
that each thread will poll at perioidic intervals. Alternatively, you could use the BackgroundWorker
class that has some support for task-cancellation (call CancelAsync
on it, and get the worker threads to test CancellationPending
periodically). If you are on .NET 4.0, you can also use the TPL.
I would recommend you to take a look at the built in synchronization primitives such as ManualResetEvent and WaitHandle. You can ask a thread if it's running or not by trying to join the thread with Thread.Join. Aborting a thread should only be done as a last resort if the thread is unresponsive.
Here is an modified example of your code that shows how you can prevent the thread from be restarted before it's been stopped properly.
public partial class MainForm : Form
{
private Thread t1;
private ThreadStart ts1;
private ManualResetEvent t1resetEvent;
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null) {
if (!t1.Join(0)) {
// The thread seems to be running.
// You have to stop the thread first.
return;
}
}
t1resetEvent = new ManualResetEvent(false);
ts1 = new ThreadStart(MyFunc);
t1 = new Thread(ts1);
t1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
// Got a thread?
if (t1 != null)
{
// Set the reset event so the thread
// knows it's time to stop.
t1resetEvent.Set();
// Give the thread four seconds to stop.
if (!t1.Join(4000)) {
// It did not stop, so abort it.
t1.Abort();
}
}
}
private void MyFunc()
{
// Long running operation...
while (true)
{
// Do someone want us to exit?
if (t1resetEvent.WaitOne(0)) {
return;
}
}
}
}
The others have given the long versions of the answer, however the obvious simple solution is to simply skip recreating the thread object:
public partial class Form1 : Form
{
Thread thread1;
ThreadStart threadStart1;
public Form1()
{
InitializeComponent();
threadStart1 = new ThreadStart(threadTarget);
thread1 = new Thread(threadStart1);
thread1.Name = "Button1 thread";
}
private void button1_Click(object sender, EventArgs e)
{
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread1.Abort();
}
private void threadTarget()
{
Console.WriteLine(Thread.CurrentThread.Name);
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(500);
}
}
}
However, I would consider reading up on Threading in .NET using one these guides (I'd recommend Joseph Albahari's guide on aborting - the author of C# in a nutshell) rather than use this method, particularly if you're performing IO or database operations which can leave the objects in unexpected states.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With