I've got a Windows Forms Application that does some data fetching from various places. Because of this I've made a thread that fetches and updates the graphical stuff (progressbar, textfields++).
But I'm having some problems quitting it, the thread that is. It goes something like this:
Thread t = new Thread(new ThreadStart(this.Loop))
t.Start();
and the Loop function
void Loop
{
while(true)
开发者_如何转开发 {
if( parent window isDisposed )
break;
/*
fetch and update stuff goes in here...
*/
Thread.Sleep(5000);
}
}
Closing the window will make the while break, but it is now disposed??
As Johann has suggested you might want to look at BackgroundWorker object. However if this is a learning project and you'd just like to familiarize yourself about threads then by all means!
What I'd suggest is adding a new volatile boolean variable, something like this.
volatile bool CancelationPending = false;
...
Thread T = new Thread(new ThreadStart(method));
CancelationPending = false;
...
void method () {
while (!CancelationPending)
{
/* do stuff*/
}
}
and on your Form you can add OnClosing event in which you can:
private void OnClosing(object sender, EventArgs e)
{
CancelationPending = true;
}
In such scenarios I often use an AutoResetEvent
for waiting inside the loop, paired with a method offering the caller to indicate that the threaded operation should be cancelled. You can make use of the return value in AutoResetEvent.WaitOne
and use that as a cancel flag in itself (it returns true
if it Set
is called, false
if it times out):
private AutoResetEvent waitHandle = new AutoResetEvent(false);
void Loop()
{
while(true)
{
/*
fetch and update stuff goes in here...
*/
if (waitHandle.WaitOne(5000))
{
break;
}
}
}
public void Cancel()
{
waitHandle.Set();
}
One simple way is to define a bool parameter that you use instead of while(true) and a method to set it to false:
bool threadRunning = false;
Thread t = new Thread(new ThreadStart(this.Loop));
threadRunning = true;
t.Start();
void Loop()
{
while(threadRunning)
{
if( parent window isDisposed )
break;
/*
fetch and update stuff goes in here...
*/
Thread.Sleep(5000);
}
}
public void stopThread()
{
threadRunning = false;
}
Bear in mind though it can still take up to 5 seconds for the thread to stop (or however long your sleep value is set for)
Note: you will need to use the 'InvokeRequired' pattern if the thread updates any controls created by other threads, see: Automating the InvokeRequired code pattern
It may be easier for you to use a BackgroundWorker object. It also supports cancellation and has built-in progress reporting capabilities.
I would use a static member of the thread to initiate a controled stop of the thread and add in the form's unload something like this:
stopToDo = true;
while (todoThread.IsAlive)
{
System.Threading.Thread.Sleep(10);
}
in the thread you have to do something like this:
if(stopToDo)
{
return;
}
If you just want your new thread to exit when the main thread (probably your GUI thread) exits, you can make your new thread a background thread:
Thread t = new Thread(new ThreadStart(this.Loop));
t.IsBackground = true;
t.Start();
精彩评论