开发者

timer inside thread

My Aim: I am having a credit card wait window. I will call a function from the client to wait for the credit card swipe. In order to avoid the program getting stuck while waiting for the credit card . I am using a delegate to run a timer. The delegate will call a timer. The timer periodically checks for the presence for the card. If it found a card it will a callback/delegate assigned by the client.

the code is given below, my questions are 1) Will the _timer_Elapsed will get called within the thread so that it will add minimum overhead to the ui window?

2) How can i call the callback/event of the base class from the timer function. I have written a protected method which will call the event/delegate in the base class. I need to开发者_Python百科 call the protected method from the timer function( which is inside a delegate in the derived class.)?

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();


No, the timer callback will not execute on the delegate-thread.

  1. How could it? A timer cannot 'break in' on a thread, that thread has to poll.
  2. This delegate-thread will terminate immediately after starting the timer. Which means you don't need this thread at all. Unless there is code not shown.

When you use a System.Threading.Timer the callback will be pushed onto the Threadpool.

To the second question (do try to ask only 1 question at a time)

  • A protected member should be accessible from an anonymous (embedded) method. Do you have a concrete problem?


From the MSDN documentation (sorry I got the wrong class the first time around)

This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing. It requires that the user code have a UI message pump available.

This is a roundabout way of saying that the event will be raised on the UI thread / message pump, i.e. the answer to your first question is yes as long as by "the thread" you mean "the UI thread".

I don't really understand your second question - what base class are you talking about?


First, that code will not compile. You cannot declare a named method from within another method. You can, however, declare an anonymous method or lambda expression and then assign it to a delegate reference.

There may not be any need to do asynchronous polling of the credit card device. You might be able to use a System.Windows.Forms.Timer and perform the polling from the Tick event which runs on the UI thread. This would be acceptable if the CheckCardsPresence is a quick operation.

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

If polling the credit card device is a time consuming operation then you will want to perform this operation on another thread to avoid blocking the 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();
    }
  }
}

Here is a cleaner implementation using a 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());
  }    
}

And to really top things off you could do this in C# 5.01 with the new await keyword. I am not sure it can get anymore succinct than that!

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

1C# 5.0 has not been released yet.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜