Eri*_*era 5 c# java multithreading
我正在使用具有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
}
Run Code Online (Sandbox Code Playgroud)
Thread.sleep()在scan()内部调用.
在Java中,我使用synchronized()来等待另一个线程调用invoke().我搜索了一整天,我看不到一个与ScheduledExecutorService和synchronized()等效的解决方法.
我希望有一个解决方法,因为我需要尽快解决这个问题.
谢谢!
我能找到的最可靠的方法是在回调中重新启动计时器。这样回调在活动时不会被中断。
Timer timer = new Timer(TimerCallback, null, 500, 0);
private void TimerCallback(Object o)
{
scan();
scand.WaitOne();
timer.Change(500, 0);
}
Run Code Online (Sandbox Code Playgroud)
重新timer.Change安排计时器。
注意:我删除了计时器启动中的重复。
顺便说一句:我删除了,GC.Collect()因为我认为这是不好的做法,并且在大多数情况下毫无用处。
此外,您可以在方法开始时获取时间(使用Stopwatch)并计算传递给timer.Change所需的时间增量:
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);
}
Run Code Online (Sandbox Code Playgroud)
这样,回调将在 500 毫秒减去执行扫描函数所花费的时间后调用。像这样设置,您可以从扫描中删除睡眠。
代码中出现双重回调的原因可能是当第一个线程仍在执行回调时,计时器在另一个线程上执行回调。
另一种解决方案可能是根本不使用计时器。只需循环并使用秒表来计算睡眠时间:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
确保在单独的线程上调用此方法(可以使用任务)