2016-03-06 23 views
1

我在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是事件处理程序,以响应客户event.As解雇你可以看到函数foo的Thread.Sleep(10分钟)使有可能事件处理程序在小于10分钟的时间间隔内触发的情况,所以在这种情况下,我需要删除池线程中的当前任务(foo())。

任何想法我该如何实现它?

+1

您可以使用[取消任务](https://msdn.microsoft.com/en-us/library/dd997396(v = vs.110).aspx)。 –

+0

你在这里没有任何线索。代替'Thread.Sleep',使用'Task.Delay'在内部使用定时器。并且通过支持使用CancellationToken取消等待来解决您的问题具有很好的副作用 –

+0

@MartinLiversage,您能举例说明我的示例中如何使用任务取消吗? – Michael

回答

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

处理此问题的一个相当简单的方法是跟踪您创建的每个路径的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将导致它在完成后引发异常。

+0

但是SetDescPointAsync函数是在ASP.NET页面后面的代码。当SetDescPointAsync函数解雇了它时,重建了所有的页面include pathsToTokens变量 – Michael

+0

@Michael那么你应该提到在你的问题中:) –

相关问题