2012-01-31 4 views
7

У меня возникла проблема с тем, как отменить эту задачу на C#. У меня нет четкого понимания обработки потоков, и я попытался использовать Googling для некоторых простых примеров кода, чтобы помочь мне, но у меня там действительно нет. Вот часть кода, над которым я работаю:Отмена задачи, которая извлекает URL-адреса асинхронно

var tasks = urls.Select(url => Task.Factory.StartNew(
state => 
{ 
    using (var client = new WebClient()) 
    { 

     lock (this) 
     { 

     // code to download stuff from URL 

     } 

    } 
}, url)).ToArray(); 

    try 
    { 
     Task.WaitAll(tasks); 
    } 
    catch (Exception e) 
    { 
     textBox2.AppendText("Error: " + e.ToString()); 
    } 

Где «urls» - это массив URL-адресов. Есть ли простой способ сделать это так, что, когда я нажимаю кнопку в своей программе, загрузка URL-адресов полностью прекращается? Кроме того, фрагмент кода, который я вставил, - это функция, которая вызывает вызовы backgroundWorker1, которые, я полагаю, могут сделать вещи немного сложнее. (Причина, почему у меня есть backgroundWorker, так что пользовательский интерфейс не блокируется во время загрузки URL-адресов.)

Если это в какой-то мере немного запутанно, вот схема того, что я пытался достичь с помощью моего код:

  • У меня есть массив URL-адресов, я хотел бы загрузить каждый URL-адрес асинхронно без блокировки пользовательского интерфейса.
  • Я бы хотел, чтобы пользователь остановил программу от загрузки URL-адресов, нажав кнопку, в значительной степени отменив нить.
  • Когда пользователь снова нажимает кнопку, программа снова загружает URL-адреса из этого массива.

Заранее спасибо.

+0

Просьба не включать теги в заголовок вопроса; это просто делает больше работы для тех из нас, которые заботятся о последовательности на SO. –

ответ

1

Не знаю, подходит ли это для этого или нет, но я смог отменить задачи, используя следующий код. Я создал форму с ListBox и ProgressBar, поэтому я поднимаю и обрабатываю ProgressChanged событие BackgroundWorker. Надеюсь, вам это поможет.

void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    CancellationTokenSource _tokenSource = new CancellationTokenSource(); 
    CancellationToken _token = _tokenSource.Token; 

    var urls = e.Argument as IEnumerable<string>; 

    _token = new CancellationToken(); 

    if (urls == null) return; 

    var i = 0; 
    var a = 100/urls.Count(); 

    var sb = new StringBuilder(); 
    var t = urls.Select(url => Task.Factory.StartNew(
        (u) =>{ 
         using (var wc = new WebClient()) 
         { 
          lock (this){ 
           var s = wc.DownloadString(u.ToString()); 
           sb.AppendFormat("{1}:{0}\r\n", "", u); 
          } 
         } 

        if (Worker.CancellationPending){ 
         //MAGIC HAPPENS HERE, IF BackgroundWorker IS REQUESTED 
         //TO CANCEL, WE CANCEL CancellationTokenSource 
         _tokenSource.Cancel(); 
        } 

        //IF CANCELATION REQUESTED VIA CancellationTokenSource 
        //THROW EXCEPTION WHICH WILL ADD TO AggreegateException 
        _token.ThrowIfCancellationRequested(); 

        //YOU CAN IGNORE FOLLOWING 2 LINES 
        i += a; 
        Worker.ReportProgress(i, u); 
    }, url, _token)).ToArray(); 

    try 
    { 
     Task.WaitAll(t); 
    } 
    catch (AggregateException age) 
    { 
     if (age.InnerException is OperationCanceledException) 
      sb.Append("Task canceled"); 
    } 
    catch (Exception ex) 
    { 
     sb.Append(ex.Message); 
    } 

    e.Result = sb; 
} 
+0

Вау, этот пример кода был очень полезен, я думаю, что мой собственный кусок кода работал, и поток был успешно отменен. Я не хочу слишком волноваться, но что-то всегда можно найти. :) – Chrispy

1

С помощью WebClient вы можете использовать метод CancelAsync для отмены асинхронной операции.

Для отмены задач, которые вы начинаете с Factory.StartNew, вы должны использовать CancellationTokenSource. Вам необходимо передать CancellationTokenSource.Token задачам (и вы можете спросить, отменен ли токен с помощью token.IsCancellationRequested), и вы должны позвонить CancellationTokenSource.Cancel(), чтобы установить токен как отмененный.

+0

Привет, я обязательно запомню это в отношении Factory.StartNew – Chrispy

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