我在我的应用程序中使用System.Timers.Timer
。每一秒我都会运行一个能完成某项工作的功能。问题是,这个函数可以阻塞一段时间(它读取然后从磁盘处理一个大文件)。我想只在其先前的"执行实例"已经完成了。我以为我可以通过Mutex
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Mutex TimerMut = new Mutex(false);
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
Console.Read();
}
private static void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
TimerMut.WaitOne();
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
TimerMut.ReleaseMutex();
}
}
}
那不起作用," foos"仍然每秒出现。我怎样才能做到这一点?
编辑:你是对的,开始一个新的线程来处理它是没有意义的。我以为只有System.Threading.Timer
在一个单独的线程中启动。
答案 0 :(得分:2)
如果你想跳过勾选,如果另一个已经工作,你可以这样做。
private readonly object padlock = new object();
private void SomeMethod()
{
if(!Monitor.TryEnter(padlock))
return;
try
{
//Do heavy work
}
finally
{
Monitor.Exit(padlock);
}
}
答案 1 :(得分:1)
如果此方法的另一次调用仍在运行,您可以按照以下模式跳过执行指定的工作:
private int isWorking = 0;
public void Foo()
{
if (Interlocked.Exchange(ref isWorking, 1) == 0)
{
try
{
//Do work
}
finally
{
Interlocked.Exchange(ref isWorking, 0);
}
}
}
您使用Mutex
的方法将导致额外的滴答等待更早的滴答完成,而不是在另一个仍在运行时跳过调用 ,这就是你说的你想要的。 (当处理这样的计时器时,常见的是想要跳过这样的刻度,而不是等待。如果你的刻度处理程序经常花费太长时间,你会得到一个巨大的等待处理程序队列。)
答案 2 :(得分:0)
我不确定你为什么要使用新线程来启动计时器,因为计时器在他们自己的线程上运行,但这是一个有效的方法。只需关闭计时器,直到完成当前间隔。
static System.Timers.Timer oTimer
public static void Main()
{
oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}
private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
oTimer.Enabled = false;
Console.WriteLine("foo");
Thread.Sleep(5000); //simulate some work
Console.WriteLine("bar");
oTimer.Enabled = true;
}
答案 3 :(得分:0)
我知道做这种事情的最简单方法:
internal static volatile bool isRunning;
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
}
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
if(isRunning) return;
isRunning = true;
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { isRunning = false; }
}
处理程序仍然运行,但它首先要确保另一个处理程序没有运行,如果是,它会立即停止。
对于更快速执行处理程序的计时器(例如每秒3-4次),这有可能比赛;在其中一个线程设置位之前,两个线程可以继续执行保护子句。您可以使用几个lock
语句来避免这种情况,类似于Mutex或Monitor:
static object syncObj = new object();
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
lock(syncObj)
{
if(isRunning) return;
isRunning = true;
}
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { lock(syncObj) { isRunning = false; } }
}
这将确保只有一个线程可以检查或修改isRunning,并且因为isRunning被标记为volatile,所以CLR不会将其值缓存为每个线程的性能状态的一部分;每个线程必须查看完全相同的内存位置以检查或更改值。