Как прекратить долго выполнять темы изящно?

У меня проблема с потоками в Delphi. Я думаю, что это распространено и в других языках. У меня есть длинный процесс, который я делаю в потоке, который заполняет список в главном окне. Но если в какой-то момент времени изменятся некоторые параметры, я должен прекратить выполнение текущего потока и начать с самого начала. Delphi предлагает завершить поток, установив Termination:=true и проверив значение этой переменной в потоке. Однако моя проблема заключается в том, что долго выполняющаяся часть скрывается в вызове библиотеки, и в этом вызове я не могу проверить переменную Termination. Поэтому мне пришлось ждать завершения этого вызова библиотеки, что влияет на всю программу.

Каков предпочтительный способ сделать в этом случае? Могу ли я немедленно убить нить?

4 ответа

Предпочтительным способом является изменение кода, чтобы он не блокировался без проверки на отмену.

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

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

Если вы не можете изменить код для проверки завершения, просто установите его приоритет очень низким и игнорируйте его, когда он вернется.

Потоки должны взаимодействовать для достижения плавного отключения. Я не уверен, предлагает ли Delphi механизм для прерывания другого потока, но такие механизмы доступны в.NET и Java, но их следует рассматривать как последний вариант, и состояние приложения после их использования является неопределенным.

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

Я написал это в ответ на похожий вопрос:

Я использую технику на основе исключений, которая довольно хорошо работала для меня в ряде приложений Win32.

Чтобы завершить поток, я использую QueueUserAPC, чтобы поставить в очередь вызов функции, которая выдает исключение. Однако выбрасываемое исключение не является производным от типа "Исключение", поэтому будет перехватываться только процедурой-оболочкой моего потока.

Я использовал это с приложениями C++Builder очень успешно. Я не знаю всех тонкостей обработки исключений Delphi vs C++, но я ожидаю, что это можно легко изменить для работы.

Другие вопросы по тегам