Как использовать thread.abort()

Я просто пытаюсь прервать поток, нажав кнопку, чтобы остановить процесс, если пользователь этого хочет, а не выходить из приложения.

Это исходный код:

 private void Abort_Click(object sender, EventArgs e)
    {
     //   thread1.Abort();
    }

    ///  Runs method 'Copy' in a new thread with passed arguments - on this way we separate it from UI thread otherwise it would freeze
    private void backgroundCopy_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e )
    {

        List<object> genericlist = e.Argument as List<object>;
        Thread thread1 = new Thread(() => Copy(genericlist[0].ToString(), genericlist[1].ToString()));
        thread1.Start();
        thread1.Join(); //Waiting for thread to finish
    }

Что я пробовал:

Я попробовал поток Abort() из события нажатия кнопки, переместив поле потока из метода, таким образом вы можете получить доступ из события нажатия кнопки, но он выдает много ошибок:

 object sender;
 System.ComponentModel.DoWorkEventArgs e;
 List<object> genericlist = e.Argument as List<object>;
 Thread thread1 = new Thread(() => Copy(genericlist[0].ToString(), genericlist[1].ToString()));



 private void Abort_Click(object sender, EventArgs e)
 {
     thread1.Abort();
 }

 ///  Runs method 'Copy' in a new thread with passed arguments - on this way we separate it from UI 
  thread otherwise it would freeze
 private void backgroundCopy_DoWork( )
 {


     thread1.Start();
     thread1.Join(); //Waiting for thread to finish
 }

Я так и сделал, но получаю ошибку:

в e и genericlist: инициализация поля не может ссылаться на нестатическое поле, метод или свойство.


person CountLessQ    schedule 19.12.2019    source источник
comment
Пожалуйста, используйте CancellationTokenSource и CancellationToken для отмены длительных фоновых процессов вместо Thread.Abort. Вы не должны использовать Thread.Abort, если вы не готовы впоследствии разорвать свой процесс. Thread.Abort немного безопаснее, чем раньше, но его по-прежнему небезопасно использовать, если вы точно не знаете, что делаете.   -  person Lasse V. Karlsen    schedule 19.12.2019
comment
Рассматривали ли вы Задачу или List<Task> с использованием CancellationTokenSource, чтобы вы могли просто передать CancellationToken Задаче(ям)? Вы можете дождаться одной задачи или использовать await Task.WhenAll() вместо использования BackgroundWorker таким образом.   -  person Jimi    schedule 19.12.2019
comment
Как правило, лучше разрешить потоку или задаче отслеживать какой-либо токен, чтобы он мог корректно завершиться самостоятельно. Thread.Abort совсем не изящный.   -  person    schedule 19.12.2019
comment
@Jimi Я близок к концу проекта, поэтому я не хочу вносить много изменений.   -  person CountLessQ    schedule 19.12.2019
comment
@LasseV.Karlsen Предположим, пользователь хочет потерять свой прогресс, просто прервать все и начать сначала.   -  person CountLessQ    schedule 19.12.2019
comment
Если вы не сделаете эти изменения сейчас, вам придется мучительно вносить их позже.   -  person Jimi    schedule 19.12.2019
comment
@Джими, у меня мертвая очередь.   -  person CountLessQ    schedule 19.12.2019
comment
@CountLessQ У нас у всех есть сроки. Добро пожаловать в клуб.   -  person    schedule 19.12.2019
comment
Вы можете использовать worker.CancelAsync(). См. пример здесь: wpf-tutorial.com/misc/cancelling-the -фоновый работник   -  person Robert Harvey    schedule 19.12.2019
comment
Определите запуск заново, если вы имеете в виду выйти из программы и запустить ее снова, тогда ладно. Но если вы имеете в виду отменить длительный процесс, а затем перезапустить его, не перезапуская программу, то нет, не используйте Thread.Abort.   -  person Lasse V. Karlsen    schedule 19.12.2019
comment
Если вы используете Thread.Abort и не знаете, как написать код, который можно будет безопасно убить, у вас будет масса проблем в будущем, которые, вероятно, начнутся сразу же, как ваш код будет запущен в производстве. Thread.Abort зарезервирован для системного кода, а не для кода пользователя, вы должны использовать правильную совместную отмену вместо принудительного уничтожения.   -  person Lasse V. Karlsen    schedule 19.12.2019
comment
Вы пропустите крайний срок, когда этот код не будет работать должным образом или даст непредсказуемые результаты в непредсказуемых случаях (если вы вообще сможете надежно заставить эту штуку работать). Использование Tasks делает его действительно проще (и на самом деле надежным).   -  person Jimi    schedule 19.12.2019
comment
@CountLessQ Вы пришли сюда за помощью к опытным программистам. Эти опытные программисты теперь говорят вам, что использование Thread.Abort() — плохая идея. Мы говорим вам это по очень веским причинам.   -  person    schedule 19.12.2019
comment
@LasseV.Karlsen допустим, вы хотите скопировать большую папку, тогда это заняло так много времени, поэтому вы прерываете ее, теряете прогресс и начинаете копировать новую папку, которая меньше и быстрее, вместо того, чтобы просто выйти из приложения, нажмите «Отмена».   -  person CountLessQ    schedule 19.12.2019
comment
Основная причина, по которой компилятор жалуется, заключается в том, что вы поместили код с ошибками не в то место, поместили его внутри метода, а не как инициализаторы полей.   -  person Lasse V. Karlsen    schedule 19.12.2019
comment
@LasseV.Karlsen, если вам нужен поток Abort() из события нажатия кнопки, вам нужно переместить поле потока из метода, чтобы вы могли получить доступ из события нажатия кнопки.   -  person CountLessQ    schedule 19.12.2019
comment
Поле потока, да, но переместите код инициализации, часть после = в метод.   -  person Lasse V. Karlsen    schedule 19.12.2019
comment
@ Эми, я ценю совет, и я тоже знаю эти причины.   -  person CountLessQ    schedule 19.12.2019
comment
Список предостережений в документации настолько длинный и исчерпывающий, что любой здравомыслящий человек будет избегать использования Thread.Abort(), если только нет абсолютно невозможного способа завершить поток любым другим способом. Учитесь на наших ошибках: не используйте Thread.Abort. docs.microsoft.com/ en-us/dotnet/api/   -  person Jim Mischel    schedule 19.12.2019
comment
@RobertHarvey, можете ли вы опубликовать свой комментарий в качестве ответа.   -  person CountLessQ    schedule 20.12.2019


Ответы (2)


Как использовать thread.abort()

Вы не используете Thread.Abort(), никогда, если только вы не выполняете аварийное завершение всего домена приложения или процесса. Вы НИКОГДА ЭТОГО НЕ ДЕЛАЕТЕ. Я надеюсь, что это очень ясно.

Вот несколько причин, по которым вы никогда этого не сделаете:

  1. Есть много лучших способов контролировать отмену асинхронного рабочего процесса, чем его прерывание.
  2. Прерывание потока не гарантирует фактического прерывания потока. Поток, который активно сопротивляется прерыванию, имеет способы отложить прерывание на неопределенное время. Это ненадежно, поэтому не используйте его.
  3. Самое главное: прерывание потока гарантирует сохранение правильности внутренних механизмов, используемых CLR для управления потоком. Не гарантируется правильность вашей программы! Прерывание потока может привести к нарушению инвариантов вашей программы интересным образом, что часто приводит к сбоям. (Упражнение: перечислите возможные последствия прерывания потока во время создания объекта с помощью финализатора)

Правильный способ структурировать программу — использовать шаблон совместной отмены и представлять асинхронную работу как задачу, которую можно отменить. Затем асинхронная работа периодически опрашивает токен, чтобы узнать, нужно ли его отменить.

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

У меня ошибка a field initializer can not reference a non static field, method or property.

Это правильно. Инициализатор поля не может использовать this каким-либо образом, включая неявное использование внутри тела лямбды. Причина этого в том, что инициализатор поля запускается до запуска тела конструктора, но именно тело конструктора инициализирует поля this. Дизайн языка пытается уберечь вас от написания здесь неприятной ошибки.

Вам нужно переместить логику инициализации в конструктор.

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

Я близок к концу проекта, поэтому я не хочу вносить много изменений.

Я уверен, что нет. Чем раньше вы начнете исправлять свои архитектурные проблемы, тем скорее вы получите правильную и безопасную реализацию.

у меня крайний срок

Это проблема управления, а не техническая. Мой совет: объясните ситуацию своему руководству. Они заслуживают того, чтобы знать, что выбор состоит в том, чтобы уложиться в срок с неправильно структурированной и, возможно, нестабильной программой, или продлить срок и реструктурировать программу в принципиальную, правильную, безопасную программу, отвечающую требованиям пользователя. Менеджмент должен иметь право принимать информированное решение о состоянии проекта, за который они вам платят.

person Eric Lippert    schedule 19.12.2019
comment
Это выглядит как отличный, исчерпывающий ответ, но я бы порекомендовал удалить раздел о сроках (и немного о том, что не нужно вносить архитектурные изменения из-за нехватки времени). Ответы должны быть действительно сосредоточены на технической части заданного вопроса, и они должны быть актуальны для широкой аудитории - материал об этих общих проблемах SWE на самом деле не соответствует ни одному из этих требований. - person halfer; 22.12.2019

Если вам нужно использовать потоки, попробуйте это. В противном случае попробуйте отменитьAsync, как показано в этой ссылке: https://www.wpf-tutorial.com/misc/cancelling-the-backgroundworker/

     // We will set this true to notify the worker threads return.
            private bool shouldAbort;
    // when hitting submit set:
    shouldAbort = false;
    void MethodThatDoesWork()
        {
                //we should stop if required
                if (shouldAbort)
                {
                    state.Stop();
                }
            //code
        }

мы должны быть уверены, что все потоки завершаются при закрытии формы. поэтому мы добавляем эти элементы управления.

   private void ItemsCopyer_FormClosing(object sender, FormClosingEventArgs e)
       {
         System.Diagnostics.Process.GetCurrentProcess().Kill();
        }

        private void btnAbort_Click(object sender, EventArgs e)
        {
            shouldAbort = true;
            btnAbort.Enabled = false;
        }
person CountLessQ    schedule 23.12.2019