Background thread not closing on exiting application - c#

I've got a strange error in my app: I have a single background thread and multiple normal threads. When I close the application, all the normal threads exit eventually, while the background one continues to work.
I've checked in the parallel stacks, and the background thread remains the only one working.
How can I check if the the application is exiting so I can exit the background thread from inside?

If your application has a reference to the background thread, call thread.Abort() method on termination of application.
Depending on used framework there are other options. For example in WPF the background thread may handle Application.Exit event:
new Thread(new ThreadStart(() =>
{
var thread = Thread.CurrentThread;
Dispatcher.Invoke((Action)delegate
{
Exit += (obj, args) => thread.Abort();
});
while (true) ; // background thread is always busy
})).Start();

Related

Why Main waits when spinning a new thread, but not so with a task

I wonder why in a console app, if I spin a new thread to run from Main, even though Main will reach the end it will wait, though if I spin up a new task, it will exit and not wait for the task to end.
e.g.
static void Main(string[] args)
{
Thread t = new Thread(new ThreadStart(SomeMethod));
t.Start();
// Main will wait, and app won't close until SomeMethod finishes
}
vs.
static void Main(string[] args)
{
Task.Run(() => SomeMethod());
// Main will close / app shuts down without waiting for SomeMethod to finish
}
When reading the documentation for the Thread.IsBackground property, you'll notice there are two types of threads, background and foreground:
... background threads do not prevent a process from terminating. Once all foreground threads belonging to a process have terminated... any remaining background threads are stopped and do not complete.
The reason why the Thread constructor prevents the Main process from terminating is because by default, it creates foreground threads, while task-based asynchronous operations automatically execute on the ThreadPool, which uses background threads by default, and will allow the process to terminate before they are completed.
You have set SomeMethod to run on a different thread so it's now asynchronous. You aren't waiting for the result so Main will just continue and just exit, killing both threads in the process.
Use:
Task.Run(async () => await SomeMethod());
Assuming SomeMethod is awaitable otherwise you can just await the result externally
Task.Run(() => SomeMethod()).Result;

Why background thread not exiting when form closes?

As I understand it, if I set _myThread.isBackground = true then the thread should exit when the form is closed. Unfortunately I'm not finding that my thread is exiting. Here is what my code looks like:
private void MainForm_Load(object sender, EventArgs e)
{
// <snip>
daemon = new Daemon();
// <snip>
}
public Daemon()
{
// Start the main thread which will do most of the connection checking and work
_mainThread = new Thread(() => MainThread(this));
_mainThread.IsBackground = true;
_mainThread.Start();
}
/// <summary>
/// This is the work that the main thread does.
/// </summary>
private void MainThread(Daemon daemon)
{
while(true)
{
try
{
// Do things.
Thread.Sleep(2000); // Sleep for a bit to not hammer.
}
catch (Exception e)
{
Logger.Exception(e);
}
}
}
I thought that since the thread is started from the form that setting isBackground=true would force it to close on form exit.
Am I missing or misinterpreting something?
Strictly speaking that the thread is a background thread prevents it from keeping the process alive. The process will stick around for as long as there is at least one non-background thread running. The UI thread is a non-background thread, and by default in a winform application closing the main thread will result in that thread completing.
So now that we have all of this we can see that, often enough, closing the main form will "kill" background processes, but there are any number of things that can stop this.
The main thread ending doesn't necessarily mean the application will end, and the UI thread will terminate. One can adjust the behavior of the application to end under different criteria, or add code to run in Main after the application finishes running.
You can also create additional non-UI threads, and if you do, they'll keep the entire process (and all of the background threads) alive.
According to documentation background thread just wont prevent the process from terminating. There is no guarantee that the thread will finish "nicely", whatever that may mean.
IsBackground = true means that when main thread ended (and all other non-background threads) - it'll stop. But what are these threads ? I believe when you close your mainform you still have one non-background thread running may be one where this form was created and ititialized.

UI Thread freezes while it shouldn't be

In a WPF application (C#, .NET 4.0, VS 2013), the following code (called from UI thread) freezes UI thread for 1 second:
new Thread(new ThreadStart(() =>
{
Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(1000);
}));
})).Start();
The Thread.Sleep() is a placeholder. In actual code it will access some UI element and do some time consuming calculation. That also runs on UI thread!
Shouldn't it be run in another thread other than the UI thread? What have I missed?
Dispatcher.BeginInvoke is designed to push operations (via a delegate) onto the UI thread. You have told it to push a Thread.Sleep(1000) onto the UI thread, so yes: the UI thread will freeze.
From MSDN
For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous.
If you wanted to do the work in the background... you were already on a background thread (before calling Dispatcher.BeginInvoke).
I suspect what you should be doing here is:
use .Invoke to gather values from the UI into the worker
do the processing on the worker
use .Invoke or .BeginInvoke to update the UI
Dispatcher.BeginInvoke executes operations on the main thread. Use this to execute on your thread:
new Thread(new ThreadStart(() =>
{
{
Thread.Sleep(1000);
};
})).Start();
like Marc already said the Dispatcher.BeginInvoke() pushes all the code int the Action to the UI Thread so the code gets executed there if you want your UI to stay responsive, do the Calculations before you call Dispatcher.Begin Invoke and then set your UI Controls in the BeginInvoke.
new Thread(new ThreadStart(() =>
{
int result = MyHeavyCalculation();
Dispatcher.BeginInvoke(new Action(() =>
{
label1.Text = result.ToString();
}));
})).Start();
Or have a look at async-await to execute methods asynchron and dont bother with UI threadsynchronization yourself. Simple Example

How To create a foreground task?

I seem to fail to create a foreground task.
my main thread is supppose to call another thread and then exit.
the other thread suppose to run forever
void MainThreadMain()
{
task_main = Task.Factory.StartNew(() => OtherThread()) ;
return;
}
void OtherThread()
{
while(true)
{
TellChuckNorrisJoke();
}
}
how can I ensure task_main will continue running even that Main Thread is dead?
I assumed il do:
task_main.IsBackgorund = false;
but no such option :\
I can make my main thread to wait a signal from my other thread that it passed to Foreground mode. but thats plain silly.
The obvious question is: why don't you run your work on the main thread?
Assuming this is not an option, you should use a Thread not a Task. Then you can set:
Thread.IsBackground = false;
This will prevent your application from terminating while the worker thread is running.

.NET C# Thread exception handling

I thought I understood this, and am a bit embarrassed to be asking, but, can someone explain to me why the breakpoint in the exception handler of following code is not hit?
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Thread testThread = new Thread(new ParameterizedThreadStart(TestDownloadThread));
testThread.IsBackground = true;
testThread.Start();
}
static void TestDownloadThread(object parameters)
{
WebClient webClient = new WebClient();
try
{
webClient.DownloadFile("foo", "bar");
}
catch (Exception e)
{
System.Console.WriteLine("Error downloading: " + e.Message);
}
}
You're creating a thread, setting it to be a background thread, and starting it. Your "main" thread is then finishing. Because the new thread is a background thread, it doesn't keep the process alive - so the whole process is finishing before the background thread runs into any problems.
If you write:
testThread.Join();
in your Main method, or don't set the new thread to be a background thread, you should hit the breakpoint.
Your thread is a Background thread (you set it so yourself). This means that when the application completes, the thread will be shut down without being given chance to complete.
Because your main has no further content, it exits immediately and both the application and your thread are terminated.
If you were to add a testThread.Join() call then your thread would complete before the app exited and you'd see the exception caught.
Most likely your background thread isn't started before Main exits - starting a new thread may take a while. Since the additional thread is a background thread it is terminated when Main exits.
For demo purposes, you could have your main method wait - e.g. on user input. This would allow the background thread to start running.
Since the new thread's IsBackground is true, it won't prevent the process from terminating. At the end of Main() the only foreground thread terminates, shutting down the process before the other thread gets that far.
Probably because the main thread is ending before the worker thread. Try adding
Console.ReadKey();
at the end of your Main method.

Categories