Какие есть варианты отмены запущенной задачи в многопоточности
Что проверяют
Знаете ли вы, что в iOS отмена почти всегда кооперативная: система ставит флаг, а остановиться должна сама задача. Следом обычно просят показать, как отменить уже выполняющуюся работу и что делать с её результатом.
Как отвечать
Пройдитесь по механизмам от старых к современным:
DispatchWorkItem:cancel()снимает с очереди блок, который ещё не начался. Уже запущенный блок продолжит работать, пока сам не проверитisCancelled;OperationиOperationQueue:cancel()выставляетisCancelled,cancelAllOperations()делает это для всей очереди. Внутриmain()флаг проверяют между шагами. Отменённая операция считается завершённой, и зависимые от неё операции всё равно запустятся, поэтому им тоже стоит смотреть на статус;- Swift Concurrency:
cancel()уTask, внутри проверкиTask.isCancelledилиtry Task.checkCancellation(), который бросаетCancellationError. Отмена родителя доходит до дочерних задач вasync letиTaskGroup, а модификатор.taskв SwiftUI сам отменяет задачу, когда вью исчезает. Для кода на колбэках естьwithTaskCancellationHandler; - отмена на уровне API:
URLSessionTask.cancel(),AnyCancellableв Combine. Здесь работу прерывает сам фреймворк, а не ваш цикл.
Сильный ответ заканчивается мыслью о результате: после отмены нельзя обновлять интерфейс устаревшими данными, поэтому перед записью в состояние проверяют, не отменена ли задача.
Где спотыкаются
Считают, что cancel() мгновенно останавливает поток. Принудительно поток не прерывается, и цикл без проверок флага досчитает до конца.
Называют семафоры и блокировки способом отмены. Это синхронизация, а самодельный флаг «стоп», который читают из нескольких потоков без атомарного доступа, сам по себе становится гонкой данных.
Забывают, что неструктурированный Task {} не отменяется вместе с тем, кто его создал. Его хранят и отменяют вручную при уходе с экрана. Вторая частая ошибка рядом: ловят CancellationError общим catch и показывают пользователю алерт об ошибке там, где он просто закрыл экран.