我在asp.net页面中有这个事件处理程序:
protected void SetDescPoint(object sender, EventArgs e)
{
try
{
ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(foo));
}
catch (Exception)
{ }
}
private void foo(object a)
{
try
{
System.Diagnostics.Debug.WriteLine("Start - " + DateTime.Now.ToString("h:mm:ss tt"));
TimeSpan minutes = TimeSpan.FromMinutes(10);
System.Threading.Thread.Sleep(minutes);
string path = UniquePath();
File.Delete(path);
System.Diagnostics.Debug.WriteLine("Deleted - " + DateTime.Now.ToString("h:mm:ss tt"));
}
catch (Exception ex)
{
Debug.WriteLine("EXCEPTION - " + ex.Message);
}
}
SetDescPoint是事件处理程序并且响应客户端事件而被触发。正如你可以看到函数foo具有Thread.Sleep(10分钟),当事件处理程序在小于10分钟的时间间隔内被触发时可能会出现这种情况,所以在这种情况下我需要删除池线程中的当前任务(foo())。
任何想法我该如何实现它?
答案 0 :(得分:1)
重写您的代码以使用Task.Delay
。这有两个好处:你不再持有一个线程(因为Task.Delay
在内部使用一个定时器),你可以使用取消令牌来取消等待:
protected CancellationTokenSource CancellationToken { get; private set; }
protected void SetDescPoint(object sender, EventArgs e)
{
try
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
this.CancellationToken = new CancellationTokenSource();
Task.Run(() => foo(this.CancellationToken.Token), this.CancellationToken.Token);
}
catch (Exception)
{ }
}
private async Task foo(CancellationToken token)
{
try
{
System.Diagnostics.Debug.WriteLine("Start - " + DateTime.Now.ToString("h:mm:ss tt"));
TimeSpan minutes = TimeSpan.FromMinutes(10);
await Task.Delay(minutes, token);
string path = UniquePath();
File.Delete(path);
System.Diagnostics.Debug.WriteLine("Deleted - " + DateTime.Now.ToString("h:mm:ss tt"));
}
catch (Exception ex)
{
Debug.WriteLine("EXCEPTION - " + ex.Message);
}
}
每当您想取消任务时,只需致电CancellationToken.Cancel()
答案 1 :(得分:1)
处理此问题的一种相当简单的方法是跟踪您创建的每个路径CancellationTokenSource
(我不确定是否有多条路径或简单路径,但以防万一),然后在事件再次发生时查找它。
将此与Task.Delay
一起使用,以非阻塞的方式异步控制,可以达到你想要的效果:
private ConcurrentDictionary<string, CancellationTokenSource> pathsToTokens =
new ConcurrentDictionary<string, CancellationTokenSource>();
protected async void SetDescPointAsync(object sender, EventArgs e)
{
CancellationTokenSource existingTokenSource;
var path = UniquePath();
if (pathsToTokens.TryGetValue(path, out existingTokenSource))
{
existingTokenSource.Cancel();
}
var cancellationTokenSource = new CancellationTokenSource();
pathsToTokens.AddOrUpdate(path, cancellationTokenSource,
(pathToFile, token) => cancellationTokenSource);
try
{
await Task.Delay(TimeSpan.FromMinutes(10), cancellationTokenSource.Token)
.ConfigureAwait(false);
}
catch (TaskCanceledException tce)
{
// Token was cancelled, do something?
}
Foo(path);
pathsToTokens.TryRemove(path, out cancellationTokenSource);
}
private void Foo(string path)
{
try
{
File.Delete(path);
Debug.WriteLine("Deleted - " + DateTime.Now.ToString("h:mm:ss tt"));
}
catch (Exception ex)
{
Debug.WriteLine("EXCEPTION - " + ex.Message);
}
}
此代码会发生的情况是,对于您创建的每个路径,您都会分配一个新的CancellationTokenSource
。每次触发事件时,都会检查现有令牌。如果它到位,这意味着事件仍然没有完成,你想要取消它。然后,您异步等待所需的时间。请注意,Task.Delay
包含在try-catch
中,因为调用CancellationTokenSource.Cancel
会导致它在完成后抛出异常。