每秒触发一次事件

R.G*_*ry 9 .net c# wpf multithreading

我有一个应用程序,需要每秒检查一次网站提要.

有时,对服务器的请求超过一秒钟.在这种情况下,应用程序需要等到第一个请求完成,然后立即启动新请求.我怎么能实现这个?

此外,请求不应冻结GUI.

G-W*_*Wiz 8

我会使用生产者 - 消费者模式的简单变体.你有两个共享整数变量的theads,一个生产者和一个消费者.生产者System.Threading.Timer每秒都会触发一次,此时Interlocked.Increment变量会调用消费者.Interlocked.Decrement当计数器大于零时,消费者逻辑反复检查馈送和计数器.消费者逻辑将受到Monitor.TryEnter处理重新入侵的保护.这是示例代码.

public static FeedCheck{
  int _count = 0;
  static object _consumingSync = new object();
  static Threading.Timer _produceTimer;

  private static void Consume() {
    if (!Monitor.TryEnter(_consumingSync)) return;

    try {
      while(_count > 0) {
        // check feed
        Interlocked.Decrement(ref _count);
      }
    }
    finally { Monitor.Exit(_consumingSync); }
  }

  private static void Produce() {
    Interlocked.Increment(ref _count);
    Consume();
  }

  public static void Start() {
    // small risk of race condition here, but not necessarily
    // be bad if multiple Timers existed for a moment, since only
    // the last one will survive.
    if (_produceTimer == null) {
      _produceTimer = new Threading.Timer(
        _ => FeedCheck.Produce(), null, 0, 1000
      );
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

用法:

FeedCheck.Start();
Run Code Online (Sandbox Code Playgroud)

.NET Threading的一个很好的资源(除了MSDN Library的东西)是Jon Skeet的文档,其中包括"更多方法" 下的生产者 - 消费者的这个例子Monitor.

顺便说一句,真正的生产者 - 消费者模式围绕着一组工作数据,一个或多个线程通过向该集合添加数据来产生工作,而一个或多个其他线程消费者通过从该集合中移除数据来工作.在上面的变体中,"工作数据"仅仅是我们需要立即检查Feed的次数的计数.

(另一种方法,而不是定时器回调调用Consume,用于定时器回调锁定和脉冲Monitor消耗等待.在这种情况下,消耗有一个无限循环,就像while(true)你开始一次它自己的线程.所以没有必要支持re-entrancy与调用Monitor.TryEnter.)