关于C#多线程和事件;
我正在尝试设置一个触发AutoReset事件的System.Threading.Timer。当事件发出信号时,代码将执行一个可能比下一个计时器滴答时间更长的任务。
在C ++中,当计时器设置自动复位事件时,如果事件已经设置,实际上没有任何反应,你只是错过了那个特定的滴答声。它运行良好,线程可以勾选设置已经设置的事件,并且没有问题。
在C#中,事件的设置在多个池线程上排队,或者在计时器线程上串行排列。我有定时器回调到一个线程但是 我不能为我的生活记住我是如何做到的,我自然而然地在StackOverflow上找到了它。
似乎定时器的回调会阻塞,直到重置AutoReset事件为止。 我无法查询事件以查看它是否已设置。
如何让系统忽略这一点?如果我正在调试应用程序中的一个线程并保持该线程,则会回退并且我得到线程耗尽或数据库连接耗尽,其中任何一个都会导致应用程序关闭。
我已经看到我可以使用System.Timers.Timer,但这需要一个同步对象。我知道我必须实现一个同步对象,但我无法弄明白。我找到了接口的规范,我似乎需要一个委托函数。在众多的回复中,我看到人们建议你只是创建一个虚拟同步对象,但这就是我绊倒的那个阶段。
我觉得我在不必要地追逐我的尾巴只是为了让系统忽略计时器滴答声。我已经尝试使用bool标志来表示线程忙时,但这看起来像一个丑陋的kludge。一个示例ISynchronizeInvoke实现非常有用。
提前感谢您提供的任何帮助。
答案 0 :(得分:1)
要在上一个滴答处理程序仍在运行时忽略滴答,您可以通过isRunning
字段轻松处理此问题:
private volatile int isRunning = 0;
public void Tick()
{
if (Interlocked.Exchange(ref isRunning, 1) == 0)
{
try
{
//do stuff
}
finally
{
isRunning = 0;
}
}
}
答案 1 :(得分:1)
你所描述的不可能发生。如果事件已设置,则AutoResetEvent.Set
不会阻止,因为此代码清楚地显示:
private System.Threading.Timer _myTimer;
private AutoResetEvent _myEvent = new AutoResetEvent(false);
private void DoIt()
{
_myTimer = new Timer(MyTimerCallback, null, 1000, 1000);
Console.WriteLine("Press Enter when done");
Console.ReadLine();
_myTimer.Dispose();
}
private void MyTimerCallback(object state)
{
_myEvent.Set();
Console.WriteLine("tick");
}
如果你运行它,它将每秒输出一次“tick”,直到你按Enter键。
也就是说,跳过刻度线的问题很容易通过制作一次性定时器并在每次滴答后重新启用它来处理。像这样:
private void DoIt()
{
// Timeout.Infinite makes it a one-shot timer
_myTimer = new Timer(MyTimerCallback, null, 1000, Timeout.Infinite);
// other code
}
private void MyTimerCallback(object state)
{
// do whatever processing is necessary
// and then restart the timer
_myTimer.Change(1000, Timeout.Infinite);
}
这样,当前一个滴答仍在处理时,计时器无法打勾。