Why the thread doesn't joins when closing application? - c#

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.

Related

Waiting for and terminating a thread after a given time without blocking in .NET 3.5

I have a WinForms application on .NET 3.5. In this form, the user triggers an operation which is executed in another thread (a BackgroundWorker to be precise) so as to not block the UI thread. I'm in MVP, so all this is being done by a presenter which interacts with an interface to the view (implemented by the Windows Form). So far so good.
I would like to introduce functionality whereby a timeout period is introduced for the background operation to complete before cancelling it. Sounds simple enough. But the background operation calls a single function on a third-party component which may never return, so the cancellation capabilities of the BackgroundWorker are of no use to me here. Also, the BackgroundWorker.RunWorkerCompleted allowed me to get back on the UI thread, so I need to wait for the timeout or success and be able to get back to my calling thread (namely the UI thread).
I tried this using a plain old Thread (which does support Abort()) and a Timer running on a second thread, but can't seem to get it to work quite right since Join() is blocking my UI thread despite the description stating that it will block "while continuing to perform standard COM and SendMessage pumping". Admittedly I assumed this implied that it would continue to process Windows Messages, which was not the case.
int timeoutInMsec = 10000;
Thread connectThread = new Thread(Connect);
Thread timerThread = new Thread(() =>
{
var timer = new System.Windows.Forms.Timer() { Interval = timeoutInMsec };
timer.Tick += (_s, _e) =>
{
timer.Stop();
if (connectThread.ThreadState == ThreadState.Running)
connectThread.Abort();
};
};
connectThread.Start();
timerThread.Start();
timerThread.Join();
connectThread.Join();
Based on this question, I tried removing the second timer thread and adding a ManualResetEvent and calling Set() when the timer ticked, or when the Connect method did indeed complete. Here, instead of Join I used WaitOne, but unfortunately this also blocks my UI thread. I also found this other question, which a CancellationTokenSource which unfortunately is not available in .NET 3.5.
So, how can I spin my worker up and be able to terminate it after a given amount of time in .NET 3.5, while at the same time be able to get back to the thread where I spun up the worker thread to execute a sort of OnCompleted handler?
Many thanks in advance!
PS: I don't have a lot of experience in multi-threaded programming in .NET, so I'm sorry if this is trivial.
If I understood your question correctly, the following algorithm should solve your problem:
As before, create a BackgroundWorker to do your background work.
In BackgroundWorker_DoWork,
create a new thread (let's call it the "third-party thread") to call your third-party library, and then
wait for the third-party thread to finish or the timeout to elapse. (*)
That way, your UI won't block, since only the Backgroundworker thread is waiting, not the main thread.
Now about the interesting part: How do you wait for the third-party thread to finish (the step marked with (*))?
My suggestion would be to simply use "loop waiting with sleep", i.e. (pseudo-code, you can use the Stopwatch class for the timeout):
do until (third-party thread has finished or x seconds have elapsed):
Thread.Sleep for 100ms
if third-party thread has not finished:
Abort it // we don't have another choice
else
Process the result
It's not best practice, but it's simple, it gets the job done and you can always replace it with fancy cross-thread-syncronization stuff (which is non-trivial to get right) once you got it all working.
It's useless to create a Forms.Timer on a non-gui thread. Don't create it on a separate thread. Why are you Joining the threads? The usage of Join is to block the current thread until the other thread is finished.
This is untested pseudo code, this is for example purpose.
public class Form1: Form1
{
private int timeoutInMsec = 10000;
private System.Windows.Forms.Timer _timer;
private Thread _connectThread;
public Form1()
{
_connectThread = new Thread(Connect);
_connectThread.Start();
_timer = new System.Windows.Forms.Timer() { Interval = timeoutInMsec };
_timer.Tick += (_s, _e) =>
{
_timer.Stop();
if (_connectThread.ThreadState == ThreadState.Running)
_connectThread.Abort();
};
};
}
private void Connected()
{
}
private void Aborted()
{
}
private void Connect()
{
try
{
DoConnect3rdPartyStuff();
this.Invoke(Connected);
}
catch(ThreadAbortException)
{
// aborted
this.Invoke(Aborted);
}
}
}

uses of creating a thread and Blocking UI

I have started a special course in multithreading but I have some fundamental issues I want to clear up. say I have a thread
Thread t1 = new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
IsCancel = false;
this.workProj.DoWorkWithRefSync(ref IsCancel);
});
t1.Start();
Followed by
while(t1.IsAlive)
{
}
or
t1.Join();
or
myAutoResetEvent.WaitOne(); // myAutoResetEvent.Set() called in thread when it finished processing
I am not sure but, this might not be a good example but looking forward to one.
I know that they are all some form of signaling from the background thread to inform the calling/UI thread that the work has completed.
But using them end up blocking the UI until the thread completes. So I would like to know a real life scenario implementation of this.
I am thinking why not just run this process on the UI thread since you don't mind blocking it.
Edit: In otherwords, I am looking for the real uses of these blocking elements such as thread.Join() etc
A real life scenario relevant to your example would be where the reference to the thread is stored in a member of the window class, and it gets checked or waited for if some event triggers such as closing the window or the application exiting.
pseudo code:
class Window
{
private Thread _thread = null;
public void OnButtonClick()
{
_thread = CreateAndStartThread();
}
public void OnCloseWindow()
{
if(null != _thread)
_thread.Wait();
}
}

Display "Busy Indicator" using background thread

I am doing some heavy computations on the main thread and these computations cannot run on a separate thread.
I want to display a "Busy Indicator" (i.e., spinning widget) on the application UI when these computations are running. As such, I cannot show the busy indicator on main thread as the UI is locked while these computations are running.
To work around this issue, I tried to move the busy indicator to separate thread. With the help of this post I am able to place the busy indicator on separate thread. However, I am not able to communicate with this thread to start or stop the busy indicator.
private HostVisual CreateBusyIndicatorOnWorkerThread()
{
// Create the HostVisual that will "contain" the VisualTarget
// on the worker thread.
HostVisual hostVisual = new HostVisual();
Thread thread = new Thread(new ParameterizedThreadStart(BusyIndicatorWorkerThread));
thread.ApartmentState = ApartmentState.STA;
thread.IsBackground = true;
thread.Start(hostVisual);
// Wait for the worker thread to spin up and create the VisualTarget.
s_event.WaitOne();
return hostVisual;
}
private static AutoResetEvent s_event = new AutoResetEvent(false);
private void BusyIndicatorWorkerThread(object arg)
{
// Create the VisualTargetPresentationSource and then signal the
// calling thread, so that it can continue without waiting for us.
HostVisual hostVisual = (HostVisual)arg;
VisualTargetPresentationSource visualTargetPS = new VisualTargetPresentationSource(hostVisual);
s_event.Set();
// Create a MediaElement and use it as the root visual for the
// VisualTarget.
visualTargetPS.RootVisual = CreateBusyIndicator();
// Run a dispatcher for this worker thread. This is the central
// processing loop for WPF.
System.Windows.Threading.Dispatcher.Run();
}
private FrameworkElement CreateBusyIndicator()
{
var busyIndicator = new MyBusyIndicator();
//busyIndicator.DataContext = this.
Binding myBinding = new Binding("IsBusy");
myBinding.Source = this;
busyIndicator.SetBinding(MyBusyIndicator.IsBusyProperty, myBinding);
}
I always gets an exception "The calling thread cannot access this object because a different thread owns it". This is because I am trying to update the busy indicator from the main thread while the busy indicator is owned by a different thread.
I have also tried an approach given in this article,
private void CreateAndShowContent()
{
Dispatcher = Dispatcher.CurrentDispatcher;
VisualTargetPresentationSource source =
new VisualTargetPresentationSource(_hostVisual);
_sync.Set();
source.RootVisual = _createContent();
DesiredSize = source.DesiredSize;
_invalidateMeasure();
Dispatcher.Run();
source.Dispose();
}
But with this approach Dispatcher.Run() nothing happens until after the completion of the computations and then the busy indicator is displayed.
I want to communicate from main thread to the thread having busy indicator. Does anyone have an approach?
There is no reason to run "heavy computations" in UI thread. Even more - this is a bad practice. Instead use BackgroundWorker which will do work, meantime alive UI-thread will show Loading/Calculating:
var worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
// This part will last at a separate thread without blocking UI.
// Excellent place for heavy computations.
}
worker.RunWorkerCompleted += (s, e) => {
// Here we're back to UI thread - so you can change states and stop animations.
}
// And finally start async computation
worker.RunWorkerAsync();
UI should contain BusyIndicator control which will be activated/stopped when you'll start/finish worker.
Please stop what you are doing... it is totally incorrect. #Anatolii Gabuza was correct... you shouldn't do any long running process using the UI thread as this will block it, making the application unusable at these times. Unless your long running process is rendering UI objects, then there really is no reason to do it using the UI thread... let us know what it is and we can help you to run it on a background thread correctly.
So you discovered that you can't display your busy indicator on the UI thread because it is busy with your long running process... at this point, most developers would realise their error, but unfortunately, not you. Instead of accepting that the long running process should be run on a background thread, you do the exact opposite and now want to display some UI element in a background thread, while blocking the UI thread with a long running process???
This is utter madness, if you want to avoid some horrendous problems, please stop. If you continue, then you'd better get used to seeing that exception:
The calling thread cannot access this object because a different thread owns it.
You need to invoke it busyContainer dispatcher. use as below
this.busyContainer.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
//update busy Container
}));
I got this from SO but cannot find it on SO
Run this on the UI thread and put in your task where very long task is
public class WaitCursor : IDisposable
{
private Cursor _previousCursor;
public WaitCursor()
{
_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
#region IDisposable Members
public void Dispose()
{
Mouse.OverrideCursor = _previousCursor;
}
#endregion
}
using (new WaitCursor())
{
// very long task
}

Thread doesn't wake up after join

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.

Join refuses to acknowledge that a child thread has terminated after the "IsAlive" property is false. C#

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.

Categories

Resources