计时器内线程

时间:2011-07-08 08:42:33

标签: c# .net multithreading timer

我的目标:我有一个信用卡等待窗口。我将从客户端调用一个函数来等待信用卡刷卡。为了避免程序在等待信用卡时卡住。我正在使用委托来运行计时器。代表将拨打计时器。计时器定期检查卡的存在。如果它找到了一张卡,它将由客户分配一个回调/代表。

下面给出了代码,我的问题是 1)是否会在线程中调用_timer_Elapsed,以便为ui窗口增加最小的开销?

2)如何从timer函数调用基类的回调/事件。我编写了一个受保护的方法,它将调用基类中的事件/委托。我需要从timer函数调用protected方法(它在派生类的一个委托中。)?

Wait wait = delegate()
{

    _timer = new Timer(3000); // Set up the timer for 3 seconds

    _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
    _timer.Enabled = true; // Enable it
    static void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // if(CheckCardsPresence())
        {
            //RaiseEvent()
            //KillTimer()
        }
        //else
        {
            // do nothing. wait more
        }

    }

};

wait.Invoke();

3 个答案:

答案 0 :(得分:1)

不,计时器回调将在委托线程上执行。

  1. 怎么可能?计时器无法“闯入”线程,该线程必须轮询。
  2. 此委托线程将在启动计时器后立即终止。这意味着你根本不需要这个线程。除非没有显示代码。
  3. 当您使用System.Threading.Timer时,回调将被推送到Threadpool。

    第二个问题(一次只试一个问题)

    • 应该可以从匿名(嵌入)方法访问受保护的成员。你有一个具体的问题吗?

答案 1 :(得分:0)

来自MSDN documentation(抱歉我第一次上错了课程)

  

此Windows计时器专为使用UI线程执行处理的单线程环境而设计。它要求用户代码具有可用的UI消息泵。

这是一种迂回的说法,即在UI线程/消息泵上引发事件,即你的第一个问题的答案是肯定的,只要你的“线程”是指“UI线程”。 / p>

我真的不明白你的第二个问题 - 你在说什么基类?

答案 2 :(得分:0)

首先,该代码不会编译。您不能在另一个方法中声明命名方法。但是,您可以声明匿名方法或lambda表达式,然后将其分配给委托引用。

可能不需要对信用卡设备进行异步轮询。您可以使用System.Windows.Forms.Timer并从在UI线程上运行的Tick事件执行轮询。如果CheckCardsPresence是一个快速操作,这是可以接受的。

public class CreditCardWaitWindow : Form
{
  private System.Windows.Timer timer = new System.Windows.Timer();

  private void Form_Load(object sender, EventArgs args)
  {
    timer.Tick += OnTick;
    timer.Interval = 3000;
    timer.Start();
  }

  private void OnTick(object sender, EventArgs args)
  {
    if (CheckCardsPresence())
    {
      RaiseEvent();
      timer.Stop();
    }
  }
}

如果轮询信用卡设备是一项耗时的操作,那么您将需要在另一个线程上执行此操作以避免阻止UI。

public class CreditCardWaitWindow : Form
{
  private System.Timers.Timer timer = new System.Timers.Timer();

  private void Form_Load(object sender, EventArgs args)
  {
    timer.Elapsed += OnElapsed;
    timer.Interval = 3000;
    timer.AutoReset = false;
    timer.Start();
  }

  private void OnElapsed(object sender, ElapsedEventArgs args)
  {
    if (CheckCardsPresence())
    {
      Invoke(
        (MethodInvoker)(() =>
        {
          RaiseEvent();
        }), null);
    }
    else
    {
      timer.Start();
    }
  }
}

以下是使用Task的清洁实现。

public class CreditCardWaitWindow : Form
{
  private void Form_Load(object sender, EventArgs args)
  {
    Task.Factory.StartNew(
      () =>
      {
        while (true)
        {
          Thread.Sleep(3000);
          if (CheckCardsPresence()) break;
        }
      }, TaskCreationOptions.LongRunning).ContinueWith(
      () =>
      {
        RaiseEvent();
      }, TaskScheduler.FromCurrentSychronizationContext());
  }    
}

最重要的是,您可以使用新的await关键字在C#5.0 1 中执行此操作。我不确定它能不能再简洁了!

public class CreditCardWaitWindow : Form
{
  private async void Form_Load(object sender, EventArgs args)
  {
    while (!CheckCardsPresence()) await Task.Delay(3000);
    RaiseEvent();
  }
}

1 C#5.0尚未发布。