← Назад к вопросам

Как в NSOperation работает под капотом функция cancel?

1.7 Middle🔥 71 комментариев
#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает отмена операции в NSOperation

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

Внутренний механизм cancel()

Вызов метода cancel() устанавливает внутренний флаг cancelled в состояние true. Это происходит атомарно через потокобезопасные примитивы для гарантии согласованности в многопоточной среде. Однако важно понимать, что отмена не прерывает выполнение операции автоматически — она лишь меняет её состояние.

Изменение состояния операции

При вызове cancel() операция переходит в состояние isCancelled. Вот как это выглядит во внутренней структуре:

class MyOperation: Operation {
    override func main() {
        // Необходимо периодически проверять isCancelled
        guard !isCancelled else { return }
        
        // Выполнение работы...
    }
}

Взаимодействие с NSOperationQueue

Когда операция находится в NSOperationQueue, очередь автоматически проверяет состояние отмены перед выполнением:

  1. Если операция отменена до начала выполнения, она никогда не запустится
  2. Если операция уже выполняется, ответственность за проверку isCancelled лежит на разработчике
// Внутренняя логика NSOperationQueue (упрощённо)
- (void)_startOperation:(NSOperation *)op {
    if ([op isCancelled]) {
        [op _finishWithState:OperationStateFinished];
        return;
    }
    // Запуск операции
}

Ключевые аспекты реализации

Атомарность и потокобезопасность

Флаг cancelled защищён внутренними блокировками (likely os_unfair_lock или pthread_mutex в современных реализациях):

- (void)cancel {
    [self.lock lock];
    _cancelled = YES;
    // Также отменяются все зависимости
    for (NSOperation *dep in self.dependencies) {
        [dep cancel];
    }
    [self.lock unlock];
}

Состояния жизненного цикла

NSOperation имеет несколько состояний:

  • isReadyisExecutingisFinished
  • isCancelled может быть установлен в любом из этих состояний

Уведомления KVO

При вызове cancel() генерируются KVO-уведомления для свойств:

  • isCancelled (изменяется с NO на YES)
  • isReady (может измениться, если были зависимости)

Практические последствия для разработчика

Кооперативная отмена

Разработчик должен явно проверять isCancelled в своей реализации:

class LongRunningOperation: Operation {
    override func main() {
        for item in largeCollection {
            // Регулярная проверка отмены
            if isCancelled {
                // Очистка ресурсов
                cleanup()
                return
            }
            process(item)
        }
    }
}

Взаимодействие с зависимостями

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

Асинхронные операции

Для асинхронных операций (где isAsynchronous = true) механизм отмены требует особого внимания:

class AsyncOperation: Operation {
    override func start() {
        guard !isCancelled else {
            isFinished = true
            return
        }
        isExecuting = true
        startAsyncWork()
    }
    
    func startAsyncWork() {
        asyncTask { [weak self] result in
            guard let self = self, !self.isCancelled else { return }
            // Обработка результата
            self.isExecuting = false
            self.isFinished = true
        }
    }
}

Отличия от GCD

В отличие от DispatchWorkItem, который можно отменить только до начала выполнения, NSOperation обеспечивает более гибкую модель отмены:

  1. Поздняя отмена — можно отменить во время выполнения
  2. Состояния — явное отслеживание через KVO
  3. Зависимости — встроенная поддержка зависимостей между операциями

Оптимизации и нюансы

  1. Множественный вызов cancel() — последующие вызовы игнорируются, флаг уже установлен
  2. Память и ресурсы — отменённая операция всё ещё удерживается в памяти до перехода в состояние isFinished
  3. Очередь отмены — NSOperationQueue может иметь внутреннюю очередь для обработки отмен

Заключение

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