如何在两个定时器之间创建延迟



目标

有两个方法:Add((和Remove((。

  • Add((方法每X秒发生一次,直到被用户停止;添加数据库对象;等待N秒;调用Remove((;

  • Remove((方法由Add((方法调用,并删除由添加的对象Add((方法。

我的代码

static bool keepGoing = true;
static System.Timers.Timer AddMethodTimer= new System.Timers.Timer();
static System.Timers.Timer RemoveMethodTimer = new System.Timers.Timer();
private static void Execute()
{
if (!keepGoing)
{
AddMethodTimer.Stop();
RemoveMethodTimer.Stop();
}
else
{
AddMethodTimer.Interval = 30; // X = 30
RemoveMethodTimer.Interval = 5; // N = 5
AddMethodTimer.Elapsed += new ElapsedEventHandler(Add);
AddMethodTimer.Start();
Thread.Sleep(RemoveMethodTimer.Interval)//In this case, N=5; 
RemoveMethodTimer.Elapsed += new ElapsedEventHandler(Remove); 
}
}
private static void Add(object source, ElapseEventArgs e)
{
//add operation
}
private static void Remove(object source, ElapseEventArgs e)
{
//remove operation
}

用户只能更改"keepGoing"变量。若为false,则计时器应停止。这整个代码是在更改时触发的(我有一个处理它的post-IActionResult。它工作得很好。当keepGoing更改时,它会输入我提供的代码(。

注意:如果对象被插入到DB中,并且用户使keepGoing为false,那么Remove((将不会执行

您可以尝试异步方式。这不会在代码中"使用"计时器。通过使用CancellationTokenSource,您可以取消任务。延误也是如此。

例如。你应该改进它,因为如果你在30秒内取消它,它仍然会调用Add and Remove。您可以使用if (!tcs.IsCancellationRequested) Add();。玩吧。

static CancellationTokenSource tcs = new CancellationTokenSource();
private static async Task ExecuteAsync()
{
while (!tcs.IsCancellationRequested)
{
await Task.Delay(30000, tcs.Token);
Add();
await Task.Delay(5000, tcs.Token);
Remove();
}
}
private static void Stop()
{
tcs.Cancel();
}
private static void Add()
{
//add operation
}
private static void Remove()
{
//remove operation
}

坚持计时器,我建议这样做:

private static System.Timers.Timer myTimer = null;
private static readonly syncObj = new object();
public static bool Execute( bool runTimer )
{
if(runTimer)
{
lock(syncObj) // myTimer access shall be thread safe
{
if(myTimer != null) return false;
// Timer is not active => activate
myTimer = new System.Timers.Timer();
myTimer.AutoReset = false; // 1-Time trigger!!
myTimer.Elapsed += AddOnTimer;
myTimer.Interval = TimeSpan.FromSeconds(30).TotalMilliseconds; // Interval is in ms!
myTimer.Enabled = true;
}
}
else
{
lock(syncObj)
{
if( myTimer == null ) return false;
myTimer.Enabled = false;
myTimer.Dispose();
myTimer = null;
}
}
return true;
}
private static void AddOnTimer(object sender, ElapsedEventArgs e)
{
AddObjToDB();
lock( syncObj )
{
if( myTimer == null ) return; // myTimer has been canceled, meanwhile
myTimer.Elapsed -= AddOnTimer;    // Instead of Add, next time
myTimer.Elapsed += RemoveOnTimer; // execute Remove
myTimer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;            
myTimer.Enabled = true;
}
}
private static void RemoveOnTimer(object sender, ElapsedEventArgs e)
{
RemoveObjFromDB();
lock( syncObj )
{
if( myTimer == null ) return; // myTimer has been canceled
myTimer.Elapsed -= RemoveOnTimer;  // Instead of Remove, next time
myTimer.Elapsed += AddOnTimer;     // execute Add
myTimer.Interval = TimeSpan.FromSeconds(30).TotalMilliseconds;
myTimer.Enabled = true;
}
}

异步方法:

public static async Task Execute( CancellationToken cancel )
{
while( !cancel.IsCancellationRequested )
{
await Task.Delay(TimeSpan.FromSeconds(30), cancel);
await AddObjToDBAsync(cancel);
await Task.Delay(TimeSpan.FromSeconds(5), cancel);
await RemoveFromDBAsync(cancel);
}
}
private static async Task AddObjToDBAsync( CancellationToken cancel )
{ 
if( !cancel.IsCancellationRequested )
{
await YourDataLayer.AddAsync( someObj ); // <= I made this up, of course. "Async all the way" is recommended.
}
}
private static async Task RemoveObjFromDBAsync( CancellationToken cancel )
{ 
if( !cancel.IsCancellationRequested )
{
await YourDataLayer.RemoveAsync( someObj );
}
}

*(我刚刚看到,Jeroen已经发布了一个异步方法。无论如何,我会把它留在这里。(

最新更新