我正在使用具有C#API的RF阅读器设备。基于其API,您需要手动调用其读取功能来读取/标记卡片。
所以我的解决方法是使用Timer来执行每个' n'秒。
我的问题是Timer连续执行,无论Thread.sleep()是否在其内部调用。
Timer timer = new Timer(TimerCallback, null, 500, 1000); // From main() method
// The action that Timer executes
private void TimerCallback(Object o)
{
scan(); // Action for reading/badging card
scand.WaitOne(); // AutoResetEvent(true)
GC.Collect(); // Force garbage collection
}
Thread.sleep()在scan()内部调用。
在Java中,我使用synchronized()来等待另一个线程调用invoke()。我搜索了一整天,但我看不到与ScheduledExecutorService和synchronized()等效的解决方法。
我希望有一个解决方法可以帮助我尽快解决这个问题。
谢谢!
答案 0 :(得分:2)
我能找到的最可靠的方法是在回调中重新启动计时器。这样,回调不会在激活时中断。
Timer timer = new Timer(TimerCallback, null, 500, 0);
private void TimerCallback(Object o)
{
scan();
scand.WaitOne();
timer.Change(500, 0);
}
timer.Change
重新安排计时器。
注意:我在Timer启动时删除了重复。
顺便说一句:我删除了GC.Collect()
,因为我认为这种做法很糟糕,在大多数情况下都没用。
此外,您可以在方法开始时获取时间(使用Stopwatch
)并计算要传递给timer的所需时间增量。更改:
Timer timer = new Timer(TimerCallback, null, 500, 0);
Stopwatch stopwatch = Stopwatch.StartNew();
private void TimerCallback(Object o)
{
var entered = stopwatch.ElapsedMilliseconds;
scan();
scand.WaitOne();
var duration = stopwatch.ElapsedMilliseconds - entered;
var delay = Math.Max(0, 500 - duration);
timer.Change(delay, 0);
}
这样,在500毫秒减去执行扫描功能所花费的时间后,将调用回调。设置如下,您可以从扫描中删除睡眠。
代码中双回调的原因可能是当第一个线程仍在执行回调时,计时器在另一个线程上执行回调。
另一种解决方案可能是根本不使用Timer。只需循环并使用秒表计算睡眠时间:
private void Scan()
{
while(scanning)
{
var entered = stopwatch.ElapsedMilliseconds;
scan();
scand.WaitOne();
var duration = stopwatch.ElapsedMilliseconds - entered;
var delay = Math.Max(0, 500 - duration);
Thread.Sleep(delay);
}
}
确保在单独的线程上调用此方法(您可以使用任务)