потеряется ли память при thread.Abort()?

262
01 июля 2017, 08:40

запускаю поток, в нем открывается форма с помощью Application.Run(frm)

через некоторое время основной поток завершает его с помощью thread.Abort() проблема в том, что иногда (редко, но все же) возникает

System.Threading.ThreadAbortException: Thread was being aborted.

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

Application.ThreadException += (s, e) => { };

т.е. просто заглушу его ошибки (в нем нет ничего критичного, это информационное окно), не останутся ли ссылки внутри этого потока и не останется ли он в памяти?

в качестве примера можно рассмотреть такой код:

    void runThread()
    {
        //запускаем поток
        var t = new Thread(showForm);
        t.Start();
        //что-то делаем
        Thread.Sleep(10000);
        // грубо завершаем дочерний поток
        t.Abort();
    }
    /// <summary>
    /// ф-ция дочернего потока
    /// </summary>
    void showForm()
    {
        Application.ThreadException += (s, e) => { }; // достаточно ли этого чтобы тихо закрыть поток?
        Application.Run(new myForm()); // на этой форме может происходить что угодно в плане отображения. 
        // данными не оперируем, только визульные фишечки. допустим, гифка крутится
    }
Answer 1

Никаких лишних ссылок не останется, сборщик мусора все приберет. Если только вы сами не наоткрываете неуправляемых ресурсов.

Тем не менее, я бы не рекомендовал решать эту задачу через Thread.Abort. Правильнее останавливать дополнительный UI-поток через Application.ExitThread или закрывая главную форму.

К сожалению, оба действия можно делать только в том потоке, где эта форма была создана. Для того, чтобы передать сигнал на закрытие в другой поток, проще всего использовать токен отмены (CancellationToken, .NET 4.0+) и контекст синхронизации (SynchronizationContext).

Получается примерно так:

void RunThread() {
    var cts = new CancellationTokenSource();
    var t = new Thread(ShowForm);
    t.Start(cts.Token);
    //что-то делаем
    Thread.Sleep(10000);
    // аккуратно завершаем дочерний поток
    cts.Cancel();
    t.Join();
}
void ShowForm(object obj)
{
    var token = (CancellationToken)obj;
    var form = new MyForm(); // В этот момент устанавливается контекст синхронизации потока
    var ctx = SynchronizationContext.Current; // В этот момент контекст синхронизации должен быть уже установлен
    using (token.Register(() => { 
        ctx.Post(_ => Application.ExitThread(), null); // Нельзя использовать Send - в этот момент мы можем уже выходить из `Application.Run` по какой-то причине
    })) { // Нельзя использовать useSynchronizationContext - он внутри использует Send
        Application.Run(form);
    }
}
READ ALSO
вызов команд PowerShell для ExchangeServer 2010 из приложения C#

вызов команд PowerShell для ExchangeServer 2010 из приложения C#

Приложение должно выполнить команды по созданию mailbox напримерЗапускаться в локальной сетке, но не с машины где стоит сам Exchange

242
Как сгененировать GUID код внутри textBox?

Как сгененировать GUID код внутри textBox?

Подскажите, есть ли способ сгенерировать GUID код, с фигурными скобками?

373
Асинхронное свойство

Асинхронное свойство

В программе есть постраничный вывод данных из БД в DataGrid

243