在C#中创建空闲循环的好方法是什么?

4

我有一个应用程序,它设置了一个FileSystemWatcher。它应该无限期地运行。

最好的方式是什么,让它在空闲循环中运行?

我目前正在执行以下操作

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

这种方式似乎有效(即可以捕获事件而不会在繁忙循环中使用核心)。

还有其他说法吗?这种方法有问题吗?


请问循环解决了什么问题? - Dzmitry Huba
它避免了繁忙循环。使用while (true){}将会占用一个核心。 - Vinko Vrsalovic
这是一个糟糕的设计,可以通过使用Mutex、Event或Semaphore来替换。 - Wim ten Brink
5个回答

9
FileSystemWatcher.WaitForChanged是一个阻塞(同步)方法。特别注意EnableRaisingEvents默认为true,因此你只需要将组件添加到表单中即可,不需要空闲循环或线程,因为组件会处理这些细节。我知道你正在使用控制台应用程序,因此你可以创建以下循环,同样不需要空闲循环,组件会处理所有细节。
    Do
        Dim i As WaitForChangedResult = Me.FileSystemWatcher1.WaitForChanged(WatcherChangeTypes.All, 1000)
    Loop Until fCancel

[更新]“注意EnableRaisingEvents默认为true。”根据微软源代码,在FileSystemWatcher组件被拖放到设计器上时才是真实的。如下所示:
    /// <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;
        } 
    }

[更新] 调用 WaitForChanged 会在 System.Threading.Monitor.Wait 语句之前和之后立即设置 EnableRaisingEvents。

谢谢你的回答。我选择了另一个答案,因为它回答了实际问题(如何进行空闲循环的好方法)。当然我也给你点了赞。 - Vinko Vrsalovic
你的问题是“如何最好地让FileSystemWatcher在空闲循环中运行?”因此,被接受的答案是不正确的。 - AMissico

6

根据您的评论,我理解您需要让应用程序无限运行,并且它是由另一个可执行文件启动的控制台应用程序。

最好使用Console.ReadLine而不是循环。 或者使用Monitor.Wait方法无限期地阻塞线程。

object sync = new object();
lock(sync)
Monitor.Wait(sync);

2

Thread.Sleep()会实现你想要的效果。但基本上,你应该使用一个操作系统方法来阻塞,以便在你期望的策略下唤醒。例如,使用Console.ReadLine()或等待一个由事件处理程序触发的互斥锁。

你不应该强制关闭你的应用程序。

如果你将代码嵌入到一个表单中,那么至少可以优雅地关闭表单,在你不使用它时,操作系统负载也会比较合理。


2
如果将运行此循环的线程标记为后台线程(Thread.IsBackground property),那么它应该可以正常工作(当所有非后台线程终止时,程序将退出)。

这样做难道不会在一段时间内没有事件发生时终止吗? - Vinko Vrsalovic

0

我不明白... 你为什么想要一个空闲循环?你想让你的应用程序无限运行吗?

那么,为什么不创建一个Windows服务或可以在系统托盘中运行的应用程序呢?

然后,我会创建一个只执行以下操作的类:

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;
   }

}

服务不可行,因为它不能要求管理员权限进行安装。系统托盘存在问题,因为有另一个进程启动此控制台应用程序并捕获其输出。 - Vinko Vrsalovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接