I've got a GUI interface which has a start and a cancel button. After starting, the main thread which is the GUI thread, is creating a second thread which will do the actual work. When pressing the cancel button, all it does is set a boolean value which tells the working thread to stop its work and end. The problem is that the main GUI thread remain stuck even though I'm sure that the working thread has finished what it was doing. Why is that?
Here is some of the code:
private Thread workerThread;
private SomeClass fs;
private void buttonSearch_Click(object sender, EventArgs e)
{
//do some initializations
fs = new SomeClass();
workerThread = new Thread(fs.WorkMethod);
workerThread.Start();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
fs.StopWork();
workerThread.Join();
}
inside SomeClass:
private bool keepWorking;
public void StopWork()
{
keepWorking= false;
}
public void WorkMethod()
{
if (keepWorking)
{
//do some stuff with recursion
}
}
does someone know why won't the main thread wake up after calling join?
I have also tried debugging to see what happens if I change the keepWorking variable to false manually and the method does reach its' end.
Your WorkMethod has a call to Invoke in there that is invoking a delegate to run on the UI thread and then block until it finishes. Since your UI thread is currently blocking on the call to Join waiting for the background thread, the UI thread is unable to call that delegate.
You now have both threads each waiting on the other, and no progress is being made. This is called a "deadlock".
Also, keepWorking should be marked as volatile as it's being accessed from multiple threads; as it stands the background thread can be accessing an outdated/cached value of that variable for quite some time after the main thread changes it. Marking it as volatile prevents the runtime from making such optimizations.
The solution here is to not block the UI thread with a call to Join. If you need to have some code execute when the background thread ends then you'll need to asynchronously fire that code when the thread finishes instead of synchronously blocking.
Related
I made a WPF application with a progressbar. The value of the progressbar is getting updated to a random value in a "while"-loop in the function "Background_Work". This function runs in a seperate thread.
If I close the window, I want to end the function (by ending the "while"-loop) and join the thread.
The problem is, that in some cases the window freezes and doesn't close.
public partial class MainWindow : Window
{
Random random;
Thread background_work;
bool running;
public MainWindow()
{
InitializeComponent();
random = new Random();
background_work = new Thread(Background_Work);
running = true;
background_work.IsBackground = true;
background_work.Start();
}
private void Background_Work()
{
while (running)
{
myBar.Dispatcher.Invoke(() => { myBar.Value = random.Next(0, 100); });
Thread.Sleep(1000);
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
running = false;
background_work.Join();
}
}
I think what's happening is a combination of two things, which together cause a deadlock.
The first is that the running field is accessed from multiple threads, but isn't synchronized. If you access data from multiple threads, it must be locked. In this case, after the main thread sets the field to false, the background thread may read it as true for a while.
The second is that you call Dispatcher.Invoke, not Dispatcher.BeginInvoke. Invoke will post a message to the dispatcher's message queue, and will wait until that message has been processed, blocking the calling thread.
So what happens is:
The dispatcher thread sets running to false
The dispatcher thread blocks, waiting for the background thread to exit
The background thread finishes its sleep, incorrectly reads running as true, posts a message to the dispatcher thread's message queue, and blocks waiting for it to be processed
The message will never be processed, because the dispatcher thread is blocked waiting for the background thread to exit
The background thread will never exit, because it is blocked waiting for the message to be processed by the dispatcher thread
Deadlock
This is happening because you're breaking a number of different cardinal rules:
Never block the UI thread. Ever.
Never access shared state from two threads without a lock (or other synchronization). Ever.
Only use Invoke over BeginInvoke if you have a really good reason.
As the comments say, use a DispatcherTimer for this.
If you do find yourself needing to cancel a background thread, use a CancellationToken.
Calling background_work.Join() blocks the currently thread while it waits for the background_work thread to naturally finish. You have that tread busy in a while loop so it never ends and thus your UI is waiting forever.
I'd suggest you avoid threads all together and use Microsoft's Reactive Framework (NuGet System.Reactive.Windows.Threading for the WPF bits).
Then you can do this:
public partial class MainWindow : Window
{
Random random;
IDisposable subscription;
public MainWindow()
{
InitializeComponent();
random = new Random();
subscription =
Observable
.Interval(TimeSpan.FromSeconds(1.0))
.ObserveOnDispatcher()
.Subscribe(_ => myBar.Value = random.Next(0, 100));
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
subscription.Dispose();
}
}
It makes things very easy.
I've got a BackgroundWorker that occasionally needs to call into the UI thread to perform some work and retrieve a result. To achieve this I'm using the following from within the background thread:
App.Current.Dispatcher.Invoke(new Action(() => { /* some code that updates local data */ });
As the app is exiting, I want to be able to tell the BackgroundWorker to quit but I want to allow it to finish any current operations. In other words, I want to call BackgroundWorkerObj.CancelAsync() and then pump messages until the thread has exited.
I've tried the following, but the Invoke() in the background thread still blocks (though the UI thread is still churning):
Worker.CancelAsync();
while (Worker.IsBusy)
{
DispatcherFrame Frame = new DispatcherFrame();
Frame.Continue = false;
Dispatcher.PushFrame(Frame);
}
What's the correct way to do this? How can the UI thread wait on the BackgroundWorker while still executing Invokes from that BackgroundWorker object?
This sort of shutdown deadlock is exactly why you shouldn't use Invoke for this purpose.
Change it to BeginInvoke(), and for communications back to the worker thread use an event.
I would use Task.Run since you're on .NET 4.0. but anyways. You have to do it the other way around. Wait for the backgroundworker to finish and then exit the application. There is no way to wait for the background thread to finish in an closing event while keeping the main thread responsive. This while loop will block the main thread and message pump until the background thread is done.
Try this
private BackgroundWorker _worker;
protected override OnFormClosing( object sender , FormClosingEventArgs e )
{
base.OnFormClosing( sender , e );
// Cancel's the closing and keeps the form alive
e.Cancel = _worker.IsBusy;
}
private void RunWorkerCompleted( object sender , RunWorkerCompletedEventArgs e)
{
// Work is done, so close the form
Close();
}
When I started main thread I also started a second thread, but the second thread still waits for the main thread. I expected that when I started a new thread it would go do work without being connected to the main thread. So why does panel1 become visible after the main thread finishing its job?
private void comboBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(threadUI));
thread.Start();
// This class is loading something from the server on the main thread
excel.get_data_from_excel(comboBox1.SelectedItem.ToString(), this);
}
private void threadUI()
{
if (panel1.InvokeRequired)
{
panel1.Invoke(new newDelegate(threadUI));
}
else
{
panel1.Visible = true;
}
}
The Invoke method will not return until the main thread executes the delegate. If you want the background thread to continue without waiting for the main thread, use BeginInvoke instead.
However, be aware that only one thing can be occurring on the main thread. You can call Invoke or BeginInvoke, but the delegate won't be processed until the main thread is idle. That is, if get_data_from_excel takes a long time, your panel1.Visible=true will not take effect until get_data_from_excel completes, comboBox1_SelectedIndexChanged_1 returns, and the main thread becomes idle.
If you truly want to make these things "parallel", you must execute get_data_from_excel in a background thread.
You're doing long running non-UI work in the UI thread.
The second thread that you create is doing nothing but calling Invoke and doing a bit of work. What Invoke does is run some code in the UI thread, which is currently busy doing some non-UI work. It won't be scheduled to run until after that work finishes.
What you should do is do that long running non-UI work in another thread, rather than the UI thread.
It looks like you're confused about Invoke().
Invoke() is used to queue up a delegate for the thread that displays panel1. However, Invoke() blocks UNTIL that delegate has run to completion. Therefore, you have your second thread blocking at Invoke().
If you would like to have an action run on the main thread, while calling it from the second thread WITHOUT blocking... then use BeginInvoke(). It will queue up the delegate and then return immediately.
Servy's Comment
Servy brings up a good point. Whats the point of the second thread, if it is just going to immediately call the first? There isn't any need to create a second thread if you are just going to immediately adjust a control's property.
But it looks like you are grabbing data from excel. That section of code should be in the second thread... and then with it's output use BeginInvoke().
if i use code just like this it also waiting for the complete next
line finishing its job
private void comboBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
panel1.Visible = true;
excel.get_data_from_excel(comboBox1.SelectedItem.ToString(), this);
}
What happens when more than one thread tries to call a form method using Invoke which updates form controls at the same time in Winforms?
static thCount = 0;
private void button1_Click(object sender, EventArgs e)
{
System.Threading.Thread t1 = new System.Threading.Thread(start);
System.Threading.Thread t2 = new System.Threading.Thread(start);
t1.Start();
t2.Start();
}
private void start()
{
System.Threading.Thread.Sleep(300);
Invoke(new MethodInvoker(guiUpdate));
}
private void guiUpdate()
{
this.label1.Text = "Updated.." + (thCount++);
this.label1.Update();
}
private void Form1_Load(object sender, EventArgs e)
{
this.label1.Text = System.Threading.Thread.CurrentThread.Name;
}
Try it out! :) You'll find that neither of them can update the UI from a background thread, instead they need to use Control.BeginInvoke to invoke work on the UI thread, in which case they will execute in the order that they call BeginInvoke.
Either of the thread will not be able to update the GUI.
You might get cross thread exception if you do not check 'InvokeRequired'.
if you still want these threads to access the same method, you can use Mutual Exclusion concept.
You can find more on Mutual Exclusion here.
This question on stack overflow also explain Mutual Exclusion in detail.
Invoke blocks until the thread has finished executing the update method.
However, this is actually only a message to the GUI thread to do this and it waits until it is done. Since the GUI thread can only execute one method at a time there is no real simultaneous execution. Nothing bad happens, but the behaviour may depend on the sequence of execution.
The sequence of execution, however, depends on which thread ever finished some guaranteed atomic (lock) operation.
Nutshell: I launch a thread from my form, then some time later use the Join method on it. It terminates but my application is stuck on the Join and refuses to acknowledge that it's done joining. What would cause this to happen? My thread is launched from a button on my form, and attempts to join from a second button on the same form.
More Info:
I have an application that uses threading to accomplish communications and number crunching. Assuming the Main Form to be the parent thread, the first child is Child1. Upon starting Child1 establishes some communications with external devices and launches 2 child threads of its own (Child2 and Child3) to process the incoming data.
When the user decides that the application is to stop processing incoming data I need Child1 to terminate (so com settings can be altered prior to resuming, if necessary). I set a stop event and Child1 exits its execution loop, the first things it does is notify Child2 and Child3 that they are no longer needed (via another stop event), Child2 and Child3 are waited for with the Join method within Child1. This works just fine.
What does not work is that the form also uses the Join method on Child1 after setting the stop event that prompted Child1 to exit it's run loop and terminate, this Join, however, waits indefinitely.
Stepping Through: When I step through my app I notice that at the moment before using Join the IsAlive property is true. After I hit Child1.Join() I can no longer get any information from the thread because it's in "JoinWaitSleep". However, if I run a while loop that causes the form thread to sleep while Child1.IsAlive is true, this works just fine. Is my second button somehow part of a thread that cannot join Child1 to it?
public void Run()
{ //Known as Child1
//code to setup coms is here
//Launch Builder threads
InsertBackgroundMonitor("Launching Collector Threads");
RunBuilders = true;
//Known as Child2 and Child3
BuildThread1 = new Thread(new ThreadStart(Cam1Builder));
BuildThread2 = new Thread(new ThreadStart(Cam2Builder));
BuildThread1.Start();
BuildThread2.Start();
while (!StopEventHandle.WaitOne(0, true))
{
//// Code that waits for coms and tosses data into lists
}
RunBuilders = false;
//Wait for threads to terminate
BuildThread1.Join();
BuildThread2.Join();
}
private void RunButton_Click(object sender, System.EventArgs e)
{
//Button for running the control thread
ControlThread = new Thread(new ThreadStart(Run));
ControlThread.Start();
}
private void StopButton_Click(object sender, System.EventArgs e)
{
if (btnStop.Enabled)
{ //Button for stopping the control thread
StopEventHandle.Set();
if (ControlThread != null)
{
while (ControlThread.IsAlive)
{
Thread.Sleep(100);
}
//somehow Join did not work
//ControlThread.Join();
}
//Update buttons
btnStart.Enabled = true;
btnStop.Enabled = false;
}
}
It's difficult to say without more code, but you have SOME resource that you've started that you're not properly shutting down.
Join() waits for the thread to be completely shut down, and all resources released before returning. If the Thread has any BackgroundWorker tasks, or if it has any spare tasks that you aren't showing still running it will not return.
Since both of the BuildThread1 and BuildThread2 are returning correctly, and Join'ing, you can be sure it's not one of those, or anything that they're doing. Look over the rest of the code. What does it do?
EDIT:
This works fine:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Thread ControlThread;
Thread BuildThread1;
Thread BuildThread2;
volatile bool RunBuilders = true;
volatile bool RunControl = true;
private void button1_Click(object sender, EventArgs e)
{
ControlThread = new Thread(new ThreadStart(Run));
ControlThread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
RunControl = false;
if (ControlThread != null)
{
while (ControlThread.IsAlive)
{
Thread.Sleep(100);
}
//somehow Join did not work
ControlThread.Join();
}
}
public void Run()
{ //Known as Child1
//code to setup coms is here
//Launch Builder threads
RunBuilders = true;
//Known as Child2 and Child3
BuildThread1 = new Thread(new ThreadStart(Cam1Builder));
BuildThread2 = new Thread(new ThreadStart(Cam1Builder));
BuildThread1.Start();
BuildThread2.Start();
while (RunControl)
{
//// Code that waits for coms and tosses data into lists
}
RunBuilders = false;
//Wait for threads to terminate
BuildThread1.Join();
BuildThread2.Join();
}
public void Cam1Builder()
{
while ( RunBuilders )
{
}
}
}
}
I can only guess at the possible issues that would cause this since I do not see the code for the Cam1Builder and Cam2Builder methods.1 The possibilities that immediately jump out at me are:
Calling Join blocks execution of the calling thread. If this is done from a UI thread then it stops the message pump. If the worker is trying to post messages to the UI thread (via Control.Invoke for example) then both threads will deadlock.
If RunBuilders is not marked as volatile or accessed inside a lock then its value, as perceived by other threads, cannot be predicted at any given point in time.
In general it is not advisable to call Join from the UI thread. UI threads are special in that they are running an indefinite loop which is dispatching and processing windows messages. This loop is initiated by calling Application.Run which you should see somewhere in your code. If you block the UI thread by calling Join or other blocking method then it cannot process queued messages. It is possible that you are using Control.Invoke to marshal the execution of a delegate on the UI thread from one of the worker threads. If this is the case then both threads will deadlock. Join blocks the UI thread waiting for the worker thread. Control.Invoke blocks the worker thread waiting for the UI thread.
Variables used as communication mechanisms between threads should be made thread-safe. In your case you are using RunBuilders as a mechanism for signaling an action on a worker thread. The problem is that since RunBuilders is neither marked as volatile nor accessed from within a lock block then its value cannot be reliably transferred to the worker thread. You may be setting its value to true in one thread, but another thread could continue to read false indefinitely.
1If you post more code I might be able to provide better insight. Specifically, I would like to see the general outline of what Cam1Builder or Cam2Builder is doing especially the parts where it is reading RunBuilders.
Did you try changing RunBuilders to volatile? Personally I don't know as I'd use a bool in this manner cross-threads, but if you're going to it should be volatile so all threads see the update instead of a stale value "cached" away by the JIT.
Other than that would need to see what the two other threads are doing.