I have a service which creates a FileSystemWatcher inside OnStart and I want the service to end only after a file is created
So I have this code
protected void OnStart()
{
try
{
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = WatchPath;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = false;
watcher.Changed += OnCreated;
watcher.EnableRaisingEvents = true;
logEvents.Write(MyLogClass.LogLevel.Info, "Watcher created");
}
}
catch (Exception ex)
{
logEvents.Write(MyLogClass.LogLevel.Info, ex.Message);
}
if (finished)
{
OnStop();
}
}
The bool "finished" is only set to true in the last line of OnCreated
private void OnCreated(object sender, FileSystemEventArgs e)
{
//Here I do all the stuff I need and then:
finished = true;
}
But even when OnCreated is not executed the service ends and I get:
"The program - has exited with code 0 (0x0)."
I've tried calling OnStop() in different parts of the code but the same thing happens anyways. I'd like the service to stay still until a given file is created and to start over when OnCreated is done, but I don't know what's wrong in this.
A FileSystemWatcher, by itself, isn't enough to keep a process running. When no events are being serviced, no threads are required, and even when one is required it'll be a background thread.
What a process needs to stay running is a foreground thread. It doesn't matter what that thread is doing, so long as at least one exists.
It doesn't look like you have any useful work for such a thread to do - but you need one. I suggest you create a thread that just waits for a ManualResetEvent to become set. You then use that, rather than your finished variable, to indicate when you want the service to shut down.
At that point, the foreground thread exits, no foreground threads are left, the process shuts down and the service becomes stopped.
Note that you have to create a new thread for this waiting work. The thread on which OnStart (and OnStop) is called doesn't "belong" to you. It's a thread that services the Service Control Manager, and you need to let it do that.
Your code is executing once and then ending.
You need a loop with a sleep timer around the main code to keep it alive. And in here embed your check for finished.
Edit:
As mentioned in the comments.
I missed that you were doing this in OnStart. The loop shouldn't be done here otherwise windows will think that you service failed to start. So you will also need to refactor this.
Related
I am trying to figure out a way to shutdown my foreground thread in the event that my application quits/terminates/etc..
From what I have tested and read about, it is to my understanding that the main thread is always last to execute. Is this always true?
If so, then could someone suggest of a way to graciously signal a shutdown of a foreground thread? (in the event of application quit) Or is this even possible?
I am kinda getting a feeling that a foreground thread should be responsible of shutting down itself (not relying on a outside signal), unless it is known that the process will not terminate/shutdown prematurely. Is this also true?
I have a couple of reasons for using a foreground thread instead of a background thread:
My thread allocates [ThreadStatic]native memory using Marshal.AllocHGlobal, and it needs to be properly released.
It is a server application and preferably it would send all the queued packets before shutting down (not essential).
For example:
volatile bool running = true;
static void Main()
{
AppDomain.CurrentDomain.ProcessExit += new
EventHandler(OnProcessExit);
var t = new Thread(ReadWrite);
t.Start();
ConsoleKeyInfo cki;
Console.WriteLine("Running..\n");
bool stopped = false;
while(!stopped)
{
// do server stuff..
.......
if (Console.KeyAvailable)
{
cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.X)
{
stopped = true;
}
}
}
}
private void ReadWrite()
{
while (running)
{
// do stuff....
....
Thread.Sleep(15);
}
FreeMemory();
}
public void EndServer()
{
FreeMemory();
running = false;
// do other stuff...
}
private void OnProcessExit(object sender, EventArgs e)
{
EndServer();
}
This results in:
stopped is made true
OnProcessExit is not called. (I have also tried explicitly calling EndServer() but got the same result
application hangs
So I suspect (but I am not sure) that since the main thread is last to execute, the program is waiting for ReadWrite to finish, which means what I am doing is not possible?
If it is not possible, I will either: Look to see if it is possible to do with background thread, or I will look into redesigning my native memory implementation.
It turns out I had no idea that native memory is freed when program is closed. Putting my thread in background will solve the rest of my issues.
Edit for future reference:
A background thread did not solve point 2, though it was not essential for me so I went ahead with this solution anyways.
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!
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
}
Suppose you have a search textbox and have a search algorithm attached to the TextChanged event, that runs with a BackgroundWorker. If there comes a new character in the textbox, i need to cancel the previous search and run it again.
I tried using events in between the main thread and the bgw, from this previous question, but I still get the error "currently busy and cannot run multiple tasks concurrently"
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void txtSearch_TextChanged(object sender, EventArgs e)
{
SearchWithBgw();
}
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
void bgw_Search_DoWork(object sender, DoWorkEventArgs e)
{
Search(txtSearch.Text, e);
}
private void Search(string aQuery, DoWorkEventArgs e)
{
int i = 1;
while (i < 3) // simulating search processing...
{
Thread.Sleep(1000);
i++;
if (bgw_Search.CancellationPending)
{
_resetEvent.Set(); // signal that worker is done
e.Cancel = true;
return;
}
}
}
EDIT To reflect answers. Don´t reuse the BackgroundWorker, create a new one:
private void SearchWithBgw()
{
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
bgw_Search = new BackgroundWorker();
bgw_Search.WorkerSupportsCancellation = true;
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
bgw_Search.RunWorkerAsync();
}
When the _resetEvent.WaitOne() call completes, the worker thread isn't actually done. It is busy returning from DoWork() and waiting for an opportunity to run the RunWorkerCompleted event, if any. That takes time.
There is no reliable way to ensure the BGW is completed in a synchronous way. Blocking on IsBusy or waiting for the RunWorkerCompleted event to run is going to cause deadlock. If you really want to use only one bgw then you'll have to queue the requests. Or just don't sweat the small stuff and allocate another bgw. They cost very little.
Create a new background worker if the old one exists.
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
Also I know you put fake code in, but you want to make sure you set _resetEvent when the code completes normally too.
Do not reuse a Backgroundworker. It is a cheap resource, it is not a Thread.
make sure your Bgw code stops, yours looks OK. The Bgw will release the Thread to the pool.
but in the mean time, create a new Task/Bgw for a new job.
You may want to unsubscribe your Completed event from the old Bgw.
I think you should consider not cancelling the background worker.
If you cancel requests and the user types faster than your server returns queries, he will not see suggestions until he is finished typing.
In interactive scenarios like this, It could be better to show responses that run behind with what the user's typing. Your user will know he can stop typing if the word he has in mind is your suggestions list.
This will be also better for your server when it is busy, because instead of many cancelled requests, who will cost something but that are ultimately not shown, there will be fewer requests whose response you actually use.
I ran into similar issues with (3d) rendering applications, where the beginner's mistake is to cancel and rerender on every mousemove. This lead to a lot of computation and little interactive feedback.
I'm creating a windows service and after installing the service, it stops and starts immediately, but it shouldn't be at all. Previously, I was getting errors that the service was not responding to the start command in a timely fashion, so I took the init code out and put it in a thread, and now I am here:
protected override void OnStart(string[] args)
{
this.EventLog.WriteEntry("ATNotifier Started");
ThreadPool.QueueUserWorkItem(WaitOnEmailsChanged);
ThreadPool.QueueUserWorkItem(Init, "IP");
}
The waitonemailschanged thread simply creates a filesystemwatcher to watch to see if the settings file (xml document) gets changed, and loads in the data from that file if that happens. For the time being, this just waits indefinitely (which is the general case, as that will only be changed a few times a year), as no changes are being made to the xml document.
The Init thread does all kinds of things, including creating and starting a System.Timers.Timer object whose Elapsed method is the meat of the service.
I can't understand why it would start and then immediately stop. I should also note that the eventviewer shows no logs from this app.
edit> I tried creating 'proper' threads, with the same results and I've removed everything except the creating and starting of the timer like so:
protected override void OnStart(string[] args)
{
this.EventLog.WriteEntry("ATNotifier Started");
m_Timer = new System.Timers.Timer(90000.0); // 1.5 mins
m_Timer.Elapsed += new ElapsedEventHandler(m_Timer_Elapsed);
m_Timer.Start();
}
and I'm still getting the same message. It's almost as if the OnStart is never being called.
It might be stopped unexpectedly if your main thread terminates on exception.
The code you posted doesn't make sense to me. Why set an event handler before creating your Timer?
m_Timer.Elapsed += new ElapsedEventHandler(m_Timer_Elapsed);
m_Timer = new System.Timers.Timer(90000.0); // 1.5 mins
Shouldn't these two lines be swapped?
The problem turned out top be that the EventLog.WriteEntry was throwing an error because there was no EventSource associated with it. see http://msdn.microsoft.com/en-us/library/xzwc042w.aspx
As far as I can recall, you must actively report to the service manager that the service has successfully started - otherwise, the OnStart method will return, and if the status change has not been reported, the service manager will assume that the service terminated without actually successfully loading itself.
Reporting your service as having started successfully is done IIRC by the Service base class, so add the following to the bottom of the OnStart method:
base.OnStart(args);
ThreadPool threads are background threads; they won't keep a process alive. I suspect you need a "proper" thread...
Try: new Thread(SomeCode).Start(); or similar.