【问题标题】:How to wait on events on a second thread如何等待第二个线程上的事件
【发布时间】:2009-07-30 18:47:08
【问题描述】:

在一个名为 Worker 的类中考虑以下代码

    FileSystemWatcher watcher = new FileSystemWatcher();
    public void Run()
    {
        watcher.Path = @"c:\queue";
        watcher.Created += new FileSystemEventHandler(watcher_Created);
        watcher.EnableRaisingEvents = true;
    }

现在这是我想对 Worker 做的事情,但显然这行不通。

        Worker worker = new Worker();
        Thread thread = new Thread(worker.Run);
        thread.Start();
        Console.ReadLine(); // something else more interesting would go here.

原因是 Run 方法结束而不是进入某种事件循环。如何让事件循环运行。 (我想我正在寻找类似 Application.Run 的东西)

【问题讨论】:

    标签: c# multithreading events


    【解决方案1】:

    未测试,但如果您希望它在线程上运行,您的“事件”循环将如下所示:

    private bool running = true;
    private AutoResetEvent waiter = new AutoResetEvent(false);
    
    public void Run()
    {
        FileSystemWatcher watcher = new FileSystemWatcher("C:\\");
        FileSystemEventArgs changes = null;
    
        watcher.Changed +=
            (object sender, FileSystemEventArgs e) => {
                changes = e;
                waiter.Set();
            };
    
        watcher.EnableRaisingEvents = true;
    
        while (running)
        {
            waiter.WaitOne();
            if (!running) break;
    
            Console.WriteLine("Path: {0}, Type: {1}",
                    changes.FullPath, changes.ChangeType);
        }
    
        Console.WriteLine("Thread complete");
    }
    
    public void Stop()
    {
        running = false;
        waiter.Set();
    }
    

    您可以将此代码放在一个类中并在单独的线程上运行(如果您愿意)。如果你想让你的主线程等待你创建的线程完成(尽管在这种情况下为什么还要创建一个线程呢?)那么你可以使用Thread.Join 方法。

    【讨论】:

      【解决方案2】:

      来自MSDN

      Worker worker = new Worker();
      Thread thread = new ThreadStart(worker.Run);
      thread.Start();
      // Not sure if you need this while
      while (!oThread.IsAlive);
      oThread.Join();
      Console.ReadLine();
      

      【讨论】:

      • 不,“while”最好用“if”代替,因为 Thread.Join() 是一个阻塞调用。
      • @Maxime:“while”用于等待线程处于活动状态。我认为在这种情况下实际上不需要它,但它并没有被用于您的想法。您建议的“如果”也不需要。
      【解决方案3】:

      BackgroundWorker 与 RunAsync() 一起使用时,将在单独的线程上运行您的逻辑。

      您想通过涉及事件循环的工作人员实现什么目标? FileSystemWatcher 基本上已经为您执行了一个事件循环,因此不清楚您要在这里实现什么。

      【讨论】:

      • 我不明白您的意思是“FileSystemWatcher 已经在执行事件循环”。一旦 Run 方法结束,线程的执行路径就完成了。然后线程停止,因此没有线程执行 FileSystemWatcher 事件。
      • watcher.EnableRaisingEvents = true;开始观察文件系统的对象,基本上开始“事件循环”。当发生更改时,将调用事件。在此处查看示例:msdn.microsoft.com/en-us/library/…
      • 我明白你现在要做什么了。您不需要在单独的线程上执行 Run()。一旦 Run() 完成,watcher 将仍然存在并监视文件系统。
      【解决方案4】:

      在应用程序准备好关闭之前,您能否不让 Run() 方法结束?也许更像:(抱歉,我是通过内存而不是在 IDE 中将其绑定,所以它可能并不完美):

      public void Run()
      {
          watcher.Path = @"C:\queue";
          watcher.Created += new FileSystemEventHandler(watcher_Created);
          watcher.EnableRaisingEvents = true;
      
          try
          {
              while(true)
                  Thread.Sleep();
          }
          catch(ThreadAbortedException)
          {
              return;
          }
      }
      

      和跑步者:

      Worker worker = new Worker();
      Thread thread = new Thread(worker.Run);
      thread.Start();
      Console.ReadLine(); // something else more interesting would go here.
      thread.Abort(); // do when ready to close the app.
      

      再想一想,你为什么要开始一个新线程来做这个?为什么不只是:

      watcher.Path = @"C:\queue";
      watcher.Created += new FileSystemEventHandler(watcher_Created);
      watcher.EnableRaisingEvents = true;
      Console.ReadLine(); // something else more interesting would go here.
      

      或者将您的 FileSystemWatcher 放在一个不会超出范围的变量中(如果是 WinForms 应用程序,则在主窗体上,或者如果是控制台应用程序,则在任何具有 Main() 方法的类上)。

      或者这里是否还有其他未显示的内容?

      【讨论】:

      • “while(true) Sleep”循环似乎不是一个好主意。你如何中止程序?此外,如果您只是为了等待某个线程完成,您可以使用 Thread.join 方法。
      • 来自原始线程的 thread.Abort() 调用会在第二个线程中导致 ThreadAbortedException 并且它应该在此时退出。同意虽然它远非完美无缺。关键是在原始帖子中,离开 Run() 方法导致观察者超出范围并被处置,因此没有更多事件。因此,“无限期地留在 Run() 中”的解决方案。虽然真的,我不认为它应该在第二个线程中完成......
      猜你喜欢
      • 2020-10-04
      • 2011-07-21
      • 2013-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-28
      相关资源
      最近更新 更多