Closing threads in Unity with C# - c#

I'm wanting to make sure that when my application quits that any and all open threads are closed. However when I try to do so I get the error telling me that there is no reference object for what I'm trying to do, even though it's all in the same class.
Can someone please help me out?
Starting / opening threads:
Thread listen_thread;
TcpListener tcp_listener;
Thread clientThread;
// Use this for initialization
void Start ()
{
IPAddress ip_addy = IPAddress.Parse(ip_address);
tcp_listener = new TcpListener(ip_addy, port);
listen_thread = new Thread(new ThreadStart(ListenForClients));
listen_thread.Start();
Debug.Log("start thread");
}
Then my attempt at closing them:
void OnApplicationQuit()
{
try
{
clientThread.Abort();
tcp_listener.Stop();
listen_thread.Abort();
}
catch(Exception e)
{
Debug.Log(e.Message);
}
}
What am I doing wrong? The threads open and do what they are suppose to just fine, but for some reason I can't close them.

You shouldn't force a thread to Abort, there is a lot of good answers on SO and web elsewhere on this topic, e.g:
Put the thread in its own process. When you want it to stop, kill the process.
How To Stop a Thread in .NET (and Why Thread.Abort is Evil)
You don't need to cancel the thread.
msdn on THread.Abort(). See remarks section.
Instead you should implement a cancalation pattern, for example via Task or BackgroundWorker classes. In this case you basically say: "stop or break whatever you doing and just exit the method". You can also roll out your own implementation: query a volatile bool or using event handles, but probably stick to the solutions already available. More info in this answer.

Related

killing a long running thread that is blocking on another child process to end

So, a little background. I have a program that creates a child process that runs long term and does some processing that we don't really care about for this question. It exists, and it needs to keep existing. So after starting that child process I start a thread that watches that child process and blocks waiting for it to end by Process.WaitForExit() and if it ends, it will restart the child process and then wait again. Now the problem is, how do I gracefully shut all of this down? If I kill the child process first, the thread waiting on it will spin it up again, so I know that the watcher thread needs to be killed first. I have been doing this by Thread.Abort() and then just catching the ThreadAbortException and returning ending the watcher thread and then I kill my child process. But I have been told that Thread.Abort() should be avoided at all costs and is possibly no longer supported in .Net core? So my question is why is Thread.Abort() so dangerous if I am catching the ThreadAbortException? and what is the best practice for immediately killing that thread so it doesn't have a chance to spin up the child thread again during shut down?
What you are looking for is way to communicate across threads. There are multiple ways to do this but they all have specific conditions applicable.
For example mutex and semaphore are available across processes. events or wait handles are specific to a given process, etc. Once you know the details of these you can use them to send signal from one thread to another.
A simple setup for your requirement can be -
Create a resetevent before spawning any of your threads.
Let the child thread begin. In your parent wait on the reset event that you have created.
Let the child thread reset the event.
In your parent thread the wait state is completed, you can take further actions, such as kicking of the thread again and waiting on it or simply cleaning up and walking out of execution.
Thread.Abort is an unclean way of finishing your processing. If you read the msdn article here - https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.abort?view=net-6.0 the remark clearly tells you that you cant be sure what current state your thread execution was in. Your thread may not get opportunity to follow up with important clean up tasks, such as releasing resources that it does not require no more.
This can also lead to deadlock if you have more complicated constructs in place, such as thread being aborted doing so from protected region of code, such as a catch block or a finally block. If the thread that calls Abort holds a lock that the aborted thread is waiting on, a deadlock can acquire.
Key to remember in multithreading is that it is your responsibility to let the logic have a clean way of reaching to completion and finish thread's execution.
Please note that steps suggested above is one way of doing it. Depending on your requirements it can be restructured/imporved further. For example, if you are spawning another process, you will require kernel level objects such as mutex or semaphore. Objects like event or flag cant work across the process.
Read here - https://learn.microsoft.com/en-us/dotnet/standard/threading/overview-of-synchronization-primitives for more information.
As mentioned by others, Thread.Abort has major issues, and should be avoided if at all possible. It can raise the exception at any point in the code, in a possibly completely unexpected location, and possibly leave data in a highly corrupted state.
In this instance, it's entirely unnecessary.
You should change the waiting thread to use async instead. For example, you can do something like this.
static async Task RunProcessWithRestart()
{
using cancel = new CancellationTokenSource();
try
{
while (true)
{
using (var process = CreateMyProcessAndStart())
{
await process.WaitForExitAsync(cancel.Token);
}
}
}
catch(OperationCanceledException)
{
}
}
static CancellationTokenSource cancel;
public static void StartWaitForProcess()
{
Task.Run(RunProcessWithRestart);
}
public static void ShutdownWaitForProcess()
{
cancel.Cancel();
}
An alternative, which doesn't require calling Cancel() from a separate shutdown function, is to subscribe to the AppDomain.ProcessExit event.
static async Task RunProcessWithRestart()
{
using var cancel = new CancellationTokenSource();
AppDomain.ProcessExit += (s, e) => cancel.Cancel();
try
{
while (true)
{
using (var process = CreateMyProcessAndStart())
{
await process.WaitForExitAsync(cancel.Token);
}
}
}
catch(OperationCanceledException)
{
}
}
public static void StartWaitForProcess()
{
Task.Run(RunProcessWithRestart);
}

How to close a worker thread early

I have multiple worker threads, in which each worker downloads an audio file. When the user closes the form in which these audio files get downloaded I want all of these worker threads to stop running.
I'm using a library that does the downloading of the audio files for me. So all I have to do in order to start downloading is audioDownloader.Execute();. This means I'm not using a while loop which I've seen used on msdb to end threads early.
I've tried aborting the threads on DownloadForm_FormClosing but when I try to reopen the download form, the audio files won't start downloading anymore. I've also tried using thread.Join() but the form just freezes... This is the code I use:
//DownloadForm.cs
private void DownloadForm_FormClosing(object sender, FormClosingEventArgs e)
{
isdownloadformclosing = true;
//each AudioFile holds a thread
foreach(AudioFile v in AudioFiles)
{
v.thread.Abort();
v.thread = null;
}
}
//AudioFile.cs
try
{
AudioDownloader.Execute();
}
catch(Exception e)
{
if(!DownloadForm.isdownloadformclosing)
DownloadForm.ShowErrorForId(this.Id, e);
}
..when I try to reopen the download form, the audio files won't start downloading anymore
you can't restart the **Abort**ed thread
Once the thread terminates, it cannot be restarted with another call to Start.
Thread.Start Method
What you can do for your "reopen", for example:
protected Thread tDownloader;
...
if(tDownloader == null || tDownloader.ThreadState == ThreadState.Unstarted || tDownloader.ThreadState == ThreadState.Stopped)
{
tDownloader = new System.Threading.Thread(() => {
...TODO...
});
....
tDownloader.Start();
}
see ThreadState Enumeration for more detail
Thread.Abort - raises a ThreadAbortException in the thread on which it is invoked, to begin the process of terminating the thread
After call, ThreadState has Aborted status, but its state has not yet changed to Stopped.
We can't really tell much without seeing the code for this AudioDownloader or AudioFile classes... either AudioDownloader should have a cancel method which (internally) deals with everything it needs to, or you need to check what's happening in AudioFile to cause the problem.
I suspect that if it's not expecting it's 'thread' object to be set to null, when you try to reuse the object it doesn't like it because it no longer has a thread... try recreating the AudioDownloader object each time your form loads - that should let it start as if it was starting from stratch again.
Like I say, without more code, not much we can do!

Thread.Abort vs Thread.Interrupt

If I need to cancel some operation on a thread, when should I use Thread.Abort vs Thread.Interrupt. I read the documentation on it but not sure which scneario should i use a particular call between two.
If there is any third way of doing it, please let me knwo about it too with pro and cons.
I would avoid using Thread.Abort at all costs. Its behavior is much safer and predictable since .NET 2.0, but there are still some pretty serious pitfalls with it. Most of the aborts inside managed code can be made safe, but not all of them. For example, I believe there are some subtle problems if an abort request is triggered during the processing of a static constructor. Nevermind, the fact that the out-of-band exception can occur at anytime giving you little control over defining where the safe points for shutdown are located.
There are several acceptable ways to terminate a thread gracefully.
Use Thread.Interrupt
Poll a stopping flag
Use WaitHandle events
Specialized API calls
I discuss these methods in my answer here.
Most suggestions are already done, but here's an example how i would do it:
ManualResetEvent _requestTermination = new ManualResetEvent(false);
Thread _thread;
public void Init()
{
_thread = new Thread(() =>
{
while (!_requestTermination.WaitOne(0))
{
// do something usefull
}
}));
_thread.Start();
}
public void Dispose()
{
_requestTermination.Set();
// you could enter a maximum wait time in the Join(...)
_thread.Join();
}
This way the dispose will wait until the thread has exited.
If you need a delay within the thread, you shouldn't add Thread.Sleep.
Use the WaitOne(delayTime). This way you will never have to wait to terminate it.
I wouldn't use Thread.Abort ever. It causes an exception at an almost arbitrary time.
Be careful with Thread.Interrupt. If you don't build in some waiting or sleeping time the thread won't be interrupted.
Be careful with Thread.Abort. If you catch the ThreadAbortException your thread will terminate right after catch + finally.
(I like to use those methods to send a signal to my thread so that it knows it's terminating time, then clean up and exit.)

How to unblock ConnectNamedPipe and ReadFile? [C#]

I have a class (NamedPipeManager) which has a thread (PipeThread) that waits for a NamedPipe connection using (ConnectNamedPipe) and then reads (ReadFile) - these are blocking calls (not-overlapped) - however there comes a point when I want to unblock them - for example when the calling class tries to stop the NamedPipeManager...
How can I interupt it? Using Thread.abort? Thread.interrupt? Is there a proper way to handle this?
Refer to the code below which illustrates my current situation
main()
{
NamedPipeManager np = new NamedPipeManager();
... do stuff ...
... do stuff ...
np.Stop(); // at this point I want to stop waiting on a connection
}
class NamedPipeManager
{
private Thread PipeThread;
public NamedPipeManager
{
PipeThread = new Thread(new ThreadStart(ManagePipes));
PipeThread.IsBackground = true;
PipeThread.Name = "NamedPipe Manager";
PipeThread.Start();
}
private void ManagePipes()
{
handle = CreateNamedPipe(..., PIPE_WAIT, ...);
ConnectNamedPipe(handle, null); // this is the BLOCKING call waiting for client connection
ReadFile(....); // this is the BLOCKING call to readfile after a connection has been established
}
public void Stop()
{
/// This is where I need to do my magic
/// But somehow I need to stop PipeThread
PipeThread.abort(); //?? my gut tells me this is bad
}
};
So, in function Stop() - how would I gracefully unblock the call to ConnectNamedPipe(...) or ReadFile(...)?
Any help would be appreciated.
Thanks,
It seems to be working on VC6.0, WinXP if I try to interrupt ConnectNamedPipe by
DeleteFile("\\\\.\\pipe\\yourpipehere");
So just specify name, not handle.
Starting with Windows Vista, there is a CancelSynchronousIO operation available for threads. I don't think there is a C# wrapper for it, so you would need to use PInvoke to call it.
Before Vista, there isn't really a way to perform such an operation gracefully. I would advise against using thread cancellation (which might work, but doesn't qualify as graceful). Your best approach is to use overlapped IO.
Recently I was in a situation, I could not use the Async Overlapped IO. I was stuck on the server side within ConnectNamedPipe. To unlock the thread and free resources, I had to connect to the same pipe as a client for a split second.
Main thread receives the stop signal
Main thread sets the stop event for the listening thread
Main thread connects to the pipe
If succeeded (always) - closes the newly created handle immediately
Listener thread unlocks
Listener thread does whatever required
This worked for me very well.
To unblock ReadFile one needs to connect and write to the pipe. Same effect epected.

Compact Framework 2.0: How can I stop a thread when an object is dispose?

I have this code:
Thread t = new Thread(() => UpdateImage(origin));
t.Name = "UpdateImageThread";
t.Start();
This code is created on a Custom Control. I want to stop this thread (if it's running) when the object is going to be dispose.
This custom control has the following method:
void IDisposable.Dispose()
{
/* My own code */
base.Dispose(true);
}
I think this is the place to put the code but:
How can I know is the thread is running?
How can I take a referece for the thread and stop it?
By the way, UpdateImage call a web service, so I think that it's waiting all of its life.
How can I finish this wait?
Thank you!
It depends a lot on what UpdateImage() does and how well it copes with the Image being disposed while it it still active. If UpdateImage() is your code and contains a loop you can tell it to stop (using a field like _stopping). If not, the best thing may be to do nothing - in the rare case of Disposing the control while the image is still updating you take the penalty of leaving it to the GC.
About how to get the Thread: By saving the reference when and where you create it, for instance int the private member _updateThread.
Now actually stopping (aborting) the thread is a (very) bad idea.
So you'll need an indicator, like
private bool _stopping = false;
And it is up to the UpdateImage() method to react to _stopping == true and stop with what it is doing.
Your Dispose() can then use
_stopping = true;
_updateThread.Join()
Save your thread variable 't' so that you can re-use it later.
Within your Dispose method you want something like:
void IDisposable.Dispose()
{
if(t.IsRunning)
{
cancelThreads = true; // Set some cancel signal that the thread should check to determine the end
t.Join(500); // wait for the thread to tidy itself up
t.Abort(); // abort the thread if its not finished
}
base.Dispose(true);
}
You should be careful aborting threads though, ensure that you place critical section of code within regions that won't allow the thread to stop before it has finished, and catch ThreadAbortExceptions to tidy anything up if it is aborted.
You can do something like this in the threads start method
public void DoWork()
{
try
{
while(!cancelThreads)
{
// Do general work
Thread.BeginCriticalRegion();
// Do Important Work
Thread.EndCriticalRegion();
}
}
catch(ThreadAbortException)
{
// Tidy any nastiness that occured killing thread early
}
}
I suggest to override the Dispose method in your Custom Control.
There you have the reference of your thread and you can call .Join() for example...

Categories