2016-03-06 5 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 (10minutes) есть может быть ситуация, когда обработчик событий запускается во временном интервале менее 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 запускает его, восстанавливается вся эта страница, включая переменную pathsToTokens – Michael

+0

@Michael Ну, вы должны упомянуть об этом в своем вопросе :) –

Смежные вопросы