How to stop a working thread

M

Marco Segurini

Hi all,

I have a simple form with a textbox and a button.
The button is used to start/stop an acquisition thread that update the
text of the textbox. Since the textbox has been create in a thread
different from the acquisition thread I use InvokeRequired/Invoke to
update the textbox.

When I click the button to stop the acquisition thread I have the
problem to notify the acquisition thread to finish and then I want the
main thread wait until the other thread finish.

A solution is:
this._thread.Abort(); // abort the acquisition thread
this._thread.Join(); // wait until acquisition thread finish
but I dislike it.

Another solution is:
set a 'public' variable (visible to acquisition thread procedure)
this._thread.Join(); // wait until acquisition thread finish
but this deadlocks the program.

Thanks for any help.

Marco


/// 'Complete' sample problem ///

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DeadLock
{
public partial class Form1 : Form
{
private System.Windows.Forms.Button _buttonStartStop;
private System.Windows.Forms.TextBox _textBox;

System.Threading.Thread _thread = null;
bool _bStopAcquisition;

public Form1()
{
InitializeComponent();
}

void MyWorkProc()
{
for (int i = 0; !this._bStopAcquisition; i = ++i % 1000)
{
SetEditBoxText(i.ToString());
}
}

delegate void MyDelegate(string str);

void SetEditBoxText(string str)
{
if (this._textBox.InvokeRequired)
{
this._textBox.Invoke(new MyDelegate(SetEditBoxText), new
object[] { str });
}
else
{
this._textBox.Text = str;
}
}

private void button1_Click(object sender, EventArgs e)
{
if (this._thread == null)
{
this._bStopAcquisition = false;
this._thread = new System.Threading.Thread(MyWorkProc);
this._thread.Start();
this._buttonStartStop.Text = "Stop";
}
else
{
//this._thread.Abort(); // I don't want to use this statement
this._bStopAcquisition = true;
this._thread.Join();
this._buttonStartStop.Text = "Start";
this._thread = null;
}
}
}
}
 
J

Jon Skeet [C# MVP]

I have a simple form with a textbox and a button.
The button is used to start/stop an acquisition thread that update the
text of the textbox. Since the textbox has been create in a thread
different from the acquisition thread I use InvokeRequired/Invoke to
update the textbox.

When I click the button to stop the acquisition thread I have the
problem to notify the acquisition thread to finish and then I want the
main thread wait until the other thread finish.

A solution is:
    this._thread.Abort(); // abort the acquisition thread
    this._thread.Join();  // wait until acquisition thread finish
but I dislike it.

Good. It's very nasty and can lead to corrupt state.
Another solution is:
    set a 'public' variable (visible to acquisition thread procedure)
    this._thread.Join();  // wait until acquisition thread finish
but this deadlocks the program.

Your boolean needs to be volatile to make sure the change is seen.

See http://pobox.com/~skeet/csharp/threads/shutdown.shtml

Jon
 
G

Göran Andersson

Marco said:
Hi all,

I have a simple form with a textbox and a button.
The button is used to start/stop an acquisition thread that update the
text of the textbox. Since the textbox has been create in a thread
different from the acquisition thread I use InvokeRequired/Invoke to
update the textbox.

When I click the button to stop the acquisition thread I have the
problem to notify the acquisition thread to finish and then I want the
main thread wait until the other thread finish.

A solution is:
this._thread.Abort(); // abort the acquisition thread
this._thread.Join(); // wait until acquisition thread finish
but I dislike it.

That's the correct reaction. It's difficult (and sometimes impossible)
to implement code for the thread to handle aborting correctly. It causes
a ThreadAbortException to be thrown in the thread whatever it happens to
be doing, so the thread has to be able to clean up correctly from
anywhere in the code.
Another solution is:
set a 'public' variable (visible to acquisition thread procedure)
this._thread.Join(); // wait until acquisition thread finish
but this deadlocks the program.

That is most likely because the worker thread is invoking a method in
the main thread, but the main thread isn't handling messages any more
because it's waiting for the worker thread to end.

You can't use Join to wait for the background thread to end. You have to
continue to handle messages in the main thread as that is needed for the
worker thread to be able to invoke a method in the main thread.

You either have to exit the event handler, or use a loop that call
Application.DoEvents.


To use a variable between threads it should be volatile. This keeps the
compiler from optimising away reads.

volatile bool _bStopAcquisition;
 
L

Lav

thread.Abort() should not be used as it throws
ThreadAbortException.Instead you can use set of thread signalling
mechanisms (ManualResetEvent) to signal a thread to start/exit.This
will let your thread do all the clean up before exiting and not when
it is in the middle of something.

Lav G
http://lavbox.blogspot.com
 
G

Göran Andersson

Lav said:
thread.Abort() should not be used as it throws
ThreadAbortException.

Yes, that was what I told the OP.
Instead you can use set of thread signalling
mechanisms (ManualResetEvent) to signal a thread to start/exit.This
will let your thread do all the clean up before exiting and not when
it is in the middle of something.

Yes, but that doesn't solve the main problem. The UI thread needs to
continue processing messages while waiting for the thread to end, as the
thread is invoking a method in the UI thread.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top