线程内的计时器
本文关键字:计时器 线程 | 更新日期: 2023-09-27 18:01:36
我的目标:我有一个信用卡等待窗口。我将从客户端调用一个函数来等待信用卡刷卡。为了避免程序在等待信用卡时卡住。我使用委托来运行计时器。这个委托会调用一个计时器。计时器定期检查卡是否存在。如果它找到一张卡片,它将调用客户端分配的回调/委托。
的代码如下,我的问题是1)将_timer_Elapsed将在线程内调用,以便它将添加最小的开销到ui窗口?
2)我如何从定时器函数调用基类的回调/事件。我写了一个受保护的方法,它将在基类中调用事件/委托。我需要从定时器函数调用受保护的方法(这是在派生类的委托内部)?
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();
不,计时器回调将不在委托线程上执行。
- 怎么可能?计时器不能在线程上"闯入",该线程必须轮询。
- 这个委托线程将在启动计时器后立即终止。这意味着你根本不需要这个线程。除非没有显示代码。
当你使用System.Threading.Timer时,回调将被推入线程池。
第二个问题(尽量一次只问一个问题)
- 受保护的成员应该可以通过匿名(嵌入式)方法访问。你有具体的问题吗?
从MSDN文档(对不起,我第一次得到错误的类)
这个Windows定时器是为单线程环境设计的,其中UI线程用于执行处理。它要求用户代码有一个可用的UI消息泵。
这是一种迂回的方式来说明事件将在UI线程/消息泵上引发,也就是说,你的第一个问题的答案是肯定的,只要你的"线程"指的是"UI线程"。
我不太明白你的第二个问题——你在说什么基类?
首先,该代码将无法编译。不能在另一个方法中声明命名方法。但是,您可以声明一个匿名方法或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());
}
}
更重要的是,你可以在c# 5.01中使用新的await
关键字。我不确定它能比这更简洁!public class CreditCardWaitWindow : Form
{
private async void Form_Load(object sender, EventArgs args)
{
while (!CheckCardsPresence()) await Task.Delay(3000);
RaiseEvent();
}
}
1 c# 5.0还没有发布