Эффективная реализация события отмены для потоков с сокращением числа? - PullRequest
3 голосов
/ 05 августа 2010

Каков наиболее эффективный способ создания события «отмена» в программе на C #, которая обрабатывает большой набор данных в цикле в отдельном потоке?

Сейчас я просто использую событие отмены, которое вызывается из моего потока пользовательского интерфейса, которое впоследствии вызывает функцию «onCancel» в потоке обработки чисел.Эта функция отмены устанавливает для переменной значение «истина», которую цикл проверки периодически проверяет, например,

Class Cruncher {  
    private bool cancel = false;

    public cruncher()
    {
        crunch();
    }

    private void crunch()  
    {   
        while(conditions AND !cancel) { crunch; }

        dispose_resources;
    }

    private void onCancel() 
    { 
        cancel = true;
    }
}

Хотя я не проверяю переменную отмены так часто, как в моем примере выше (и фактически не выполняет отмену NOT), Я все же хотел бы максимально оптимизировать этот метод хруста.Любые примеры, где это делается более эффективно, было бы очень приятно видеть.

Ответы [ 5 ]

3 голосов
/ 05 августа 2010

Событие / флаг отмены должно быть volatile ... Я задал очень похожий на ваш вопрос: Безопасно ли использовать логический флаг, чтобы остановить запуск потока в C #

Я бы также порекомендовал, чтобы при отмене ваших потоков вы ожидали их отмены, используя что-то похожее на C # версию CountDownLatch . Это полезно, если вы хотите гарантировать, что поток будет отменен.

1 голос
/ 06 августа 2010

Я рекомендую использовать модель унифицированного отмены , которая была представлена ​​в .NET 4.0 (если вариант .NET 4.0).

Это очень эффективно и позволяет интегрировать отмену с Task объектами и Parallel LINQ.

1 голос
/ 05 августа 2010

Тем более что он запускается через пользовательский интерфейс, я бы порекомендовал просто использовать BackgroundWorker , который уже есть в фреймворке, тем более, что он будет хорошо выполнять ход выполнения и события done в потоке пользовательского интерфейса (так чтовам не нужно вызывать его через себя).

Тогда вы можете просто использовать вызов CancelAsync ().По общему признанию, это не сильно отличается от того, что вы уже делаете, просто уже сделано в фреймворке (включая логику синхронизации потоков)

Как упоминал Джон, вы все равно захотите сделать совместную отмену (проверка CancellationPending в вашем DoWork для использования BackgroundWorker), так как параметр «прервать / прервать поток» - это то, чего вы хотите избежать, если это возможно.

Если в .NET 4 вы можете использовать TPL и newПоддержка отмены , но опять же она сфокусирована на совместной отмене.

1 голос
/ 05 августа 2010

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

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

Если вам когда-либо понадобится выполнить какое-либо ожидание, однако (в рабочем потоке), , тогда вы можете улучшить положение, используя форму ожидания (например, Monitor.Wait), которая позволяет отменять потокчтобы разбудить любые ожидающие темы рано.Это не сделает нормальную работу более эффективной, но позволит быстрее завершать потоки в случае отмены.

0 голосов
/ 05 августа 2010

я бы сделал это так же. я бы также добавил Thread.Sleep в цикл, чтобы получить контроль над основным потоком.

http://msdn.microsoft.com/en-us/library/7a2f3ay4%28VS.80%29.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...