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!
Related
I've inherited some code from a previous developer and the app occasionally gives a thread abort exception when performing a certain task.
private void popup()
{
Thread th = new Thread(() =>
{
try
{
OpenForm();
}
catch (ThreadAbortException ex)
{
Console.WriteLine("Thread was forcibly aborted");
}
});
th.Start();
while (fromflag)
{
}
th.Abort();
}
The thread opens a popup with an animated loading gif, downloads files from a server and then completes. I set fromflag to false when done.
I can't set a timer as it can take any time to download the files.
How can I write this differently so then I don't have to use th.Abort and the thread closes itself when complete?
You are opening a form on anotehr thread? That is some pretty bad design.
Usually all forms should be created by the GUI thread. If anotehr thread needs soemthing written, that is something Invoke is there for.
Without showing us the actuall code that is run in the thread (presumably contained in OpenForm()) we can not help you debugging at all.
While I can understand why the programmer used this shortcut (doing idle animations can require extra threads depending on teh Dispaly technolgoy), I still find this a bad design that should be reworked.
I try my windows phone app running in the background. Using a While loop that starts at leaving the app, everything works fine. But when I go into the app again, the app hangs in the infinite loop and does not load. That's why I have written a condition in the while loop, but as long as the while loop is running, no other code is considered. Is there an asynchronous while loop or something to solve the problem.
Here is my code from App.xaml.cs:
private void Application_Closing(object sender, ClosingEventArgs e)
{
WhileLoop();
}
private void Application_Activated(object sender, ActivatedEventArgs e)
{
Continue = false;
}
static bool Continue = false;
void WhileLoop()
{
Continue = true;
while(Continue == true)
{
//do something in background
}
}
It's hard for me to guess what you mean by running in Background. If you mean running under lock screen, then it's possible by Disabling IdleDetection, but that's not probably what you want to achieve as I see Closing Event and so on.
In other case when programming Windows Phone, you must know few things:
as #dcastro said in comment you have limited time when App is Closing or Dectivated,
when App is Closing, then no method, thread or anything will "survive" (or shouldn't)
when App is Deactivated - all Threads, BackroundWorkers (allmost everything connected with your App) is stopped, as MSDN says:
When the user navigates forward, away from an app, after the Deactivated event is raised, the operating system will attempt to put the app into a dormant state. In this state, all of the application’s threads are stopped and no processing takes place, but the application remains intact in memory.
the other problem is when your App is Tombstoned, then most of its resources is released,
you may perform some actions in the background by using Background Agents
or you may try to save the state of your App in IsolatedStorage or PhoneApplicationService State, (you can read more about it Here ) - save upon Deactivation, then restore upon Activation
Hope this helps.
You will need to move your loop onto a BackgroundWorker because at the minute once the while loop starts it will hog the CPU in the UI thread which means no other messages will get processed i.e. your Application_Activated event.
The problem is you are trying to break out of an infinite loop which is running in the same thread. If your while loop was on a different thread (i.e. not hogging the UI thread) then your code should work. However, I think there are better ways of doing this without using
An infinite loop
A static field
For example, a more robust approach would be to keep a reference to a BackgroundWorker on Application_Closing and then on Application_Activated you could call CancelAsync on it, this would allow you to use the CancellationPending property inside your BW for a safer shutdown of the background process.
using System.Threading;
ManualResetEventSlim waitEvent = new ManualResetEventSlim(false); // start in the unsignaled state
async void Application_Closing(object sender, ClosingEventArgs e)
{
await MyLoop(); // execute asynchronously
waitEvent.Wait(); // wait for a signal to continue
}
void Application_Activated(object sender, ActivatedEventArgs e)
{
waitEvent.Reset(); // set unsignaled
}
Task MyLoop()
{
while(true)
{
if(condition)
break;
}
waitEvent.Set(); // signal the app to continue
}
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.
I have three threads in total. The first is the main UI thread, which starts a System.Threading.Thread (ExperimentThread), which in turn starts a BackgroundWorker (WorkerThread).
MainThread and WorkerThread both access a shared resource. I synchronise access to this resource with the following object:
private static readonly Object LockObject = new Object();
which I use as follows in the main loop of each thread:
lock (LockObject)
{
// Do something with shared resource here.
}
A cut-down version of ExperimentThread is as follows:
public void RunExperiment
{
while (!bStopThread)
{
lock (LockObject)
{
// Do something with shared resource here.
}
if (bStopThread)
{
break;
}
else
{
Application.DoEvents();
Thread.Sleep(250);
}
}
}
And for completeness here is the DoWork method of WorkerThread:
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker Worker = sender as BackgroundWorker;
for (int X = 0; X < 200; X++)
{
if (Worker.CancellationPending)
{
e.Cancel = true;
return;
}
lock (LockObject)
{
// Do something with shared resource here.
}
}
}
This seems to work fine when both threads are running freely.
At some point the UI thread will terminate the ExperimentThread by setting one of its boolean fields to true and then wait for it to end, as follows:
if (ExperimentThread.IsAlive)
{
ExperimentThread.StopThread = true;
ExperimentThread.Join(); // this line seems to cause the deadlock?
}
As soon as Join() is called, a deadlock occurs on the shared resource being accessed by ExperimentThread and WorkerThread, and my application hangs indefinitely. This happens maybe 9 out of 10 times.
If I remove ExperimentThread.Join() from the code snippet above, the deadlock never occurs, and ExperimentThread appears to terminate gracefully (it then goes on to terminate WorkerThread by calling CancelAsync()).
Any ideas what could be the problem here?
(P.S. I've been using Console.WriteLine() to determine when locks are taken and released, which is what has lead me to believe there's a deadlock. Is there a better to determine this, I could be wrong?)
Is there a better to determine this, I could be wrong?
A better way to check this is to use something like the Concurrency Visualizer available in higher level SKUs of Visual Studio. It will allow you to see exactly what has locked each thread, and what handles threads are waiting on, etc.
As for the exact reason you are getting a deadlock - there isn't enough code to determine this, but common issues are:
ExperimentThread and the main thread (with the Join() call) are both locking on the same object - ie: within a lock(LockObject) statement.
ExperimentThread is using Control.Invoke to marshal a call back onto the UI thread. Since the UI thread is blocked (waiting on the Join()), it can never process messages, which will prevent ExperimentThread from completing.
That being said, in general, I would recommend using Task or Task<T> instead of a new Thread if you're using .NET 4 or higher. Task provides a much nicer API for working with threads, including allowing continuations instead of blocking. C# 5 extends this to even allow you to asynchronously wait for the task to complete.
Supose you have a form with a button that starts/stops a thread (NOT pausing or interrupting, I really need to stop the thread !)
Check out this code:
Constructor()
{
m_TestThread = new Thread(new ThreadStart(ButtonsThread));
m_bStopThread = false;
}
ButtonClick
{
// If the thread is not running, start it
m_TestThread.Start();
// If the thread is running, stop it
m_bStopThread = true;
m_TestThread.Join();
}
ThreadFunction()
{
while(!m_bStopThread)
{
// Do work
}
}
2 questions (remember CF):
- How can I know if the thread is running (I cannot seem to access the m_pThreadState, and I've tried the C++ GetThreadExitCode(), it give false results) ?
- Most important question : if I have stopped the thread, I cannot restart it, most probably because the m_TestThread.m_fStarted is still set (and it is private so I cannot access it) ! And thus m_TestThread.Start() generates an exception (StateException).
Stopping the thread with an Abort() doesn't solve it. If I put my m_TestThread = null; it works, but then I create a memory leak. The GC doesn't clean up either, even if I wait for xx seconds.
Anybody has an idea ? All help highly appreciated !
Grtz
E
You can use Thread.Suspend and Thread.Resume for stopping/restarting the thread.
For checking the thread's status you can use Thread.ThreadState.