Good way to create an idle loop in C#?

6k views Asked by At

I have an app it sets up a FileSystemWatcher. It should run indefinitely.

What is the best way to have it run in an idle loop?

I'm currently doing

FileSystemWatcher watch = ... //setup the watcher
watch.EnableRaisingEvents = true;
while (true) 
{
    Thread.Sleep(int.MaxValue);
}

which seems to work (ie, captures the events and doesn't use up a core in a busy loop).

Any other idiom? Any problem with this approach?

5

There are 5 answers

0
Ahmed On BEST ANSWER

As I understood from your comment you need your application to run indefinitely and it is a console app that is lunched by another executable.

It is better to use Console.ReadLine instead of looping. or use Monitor.Wait method to block the thread indefinitely

object sync = new object();
lock(sync)
Monitor.Wait(sync);
0
Spence On

Thread.Sleep() will do what you want. But basically you should block using an OS method that will wake upon your desired strategy. Eg. a Console.ReadLine() or upon a mutex which is hit by your event handler to go away.

You shouldn't have to kill your app to make it shut.

If you embed the code on a form then at least the form can be killed nicely, with a reasonable OS load when you aren't using it.

1
Frederik Gheysels On

I do not understand ... Why do you want and idle loop ? Do you want to have your application run indefinitely ?

Then, why don't you create a Windows Service, or an application that can be run in the system tray ?

Then, what I would do is create a class which just does this:

public class Foo
{
   private FileSystemWatcher _fs;

   private volatile bool _stopped = false;

   public Foo()
   {
       _fs = new FileSystemWatcher();
       ...
   }

   public void Start()
   {
       _stopped = false;
       Thread t = new Thread (new ThreadStart(DoWork));
       t.Start();
   }

   private void DoWork()
   {
       while( !_stopped )
       {
           Thread.Sleep(1);
       }
   }

   public void Stop()
   {
       _stopped = true;
   }

}
1
chris166 On

If you mark the thread where this loop is running as a background thread (Thread.IsBackground property) then it should work fine (the program will exit when all non background threads terminate)

2
AMissico On

FileSystemWatcher.WaitForChanged is blocking (synchronous). There is absolutely no need for an idle loop, especially because you are handling events. Note EnableRaisingEvents defaults to true. Therefore, all you have to do is add the component to a form. There is no idle loop. There is no threading because the component takes care of that.

I understand you are using a Console Application. Therefore, you can create the following loop. Again, no need for an idle loop. The component takes care of all the details.

    Do
        Dim i As WaitForChangedResult = Me.FileSystemWatcher1.WaitForChanged(WatcherChangeTypes.All, 1000)
    Loop Until fCancel

[update] "Note EnableRaisingEvents defaults to true." As per the Microsoft source code, this is only true if the FileSystemWatcher component is dropped onto a designer. As shown below:

    /// <internalonly/>
    /// <devdoc>
    /// </devdoc>
    [Browsable(false)] 
    public override ISite Site {
        get { 
            return base.Site; 
        }
        set { 
            base.Site = value;

            // set EnableRaisingEvents to true at design time so the user
            // doesn't have to manually. We can't do this in 
            // the constructor because in code it should
            // default to false. 
            if (Site != null && Site.DesignMode) 
                EnableRaisingEvents = true;
        } 
    }

[update] Calling WaitForChanged sets EnableRaisingEvents immediately before and after the System.Threading.Monitor.Wait statements.