Должно ли использование NSLocking всегда быть обернуто в @try /@finally?

#objective-c #cocoa #exception-handling #locking

#objective-c #какао #обработка исключений #блокировка

Вопрос:

Учитывая NSLocking объект Cocoa (например, an NSLock ) и некоторый нетривиальный код, который должен выполняться во время удержания блокировки:

Чтобы гарантировать, что блокировка всегда снимается, всегда ли следует использовать следующую идиому?

 NSLock *mutex = // get lock from somewhere
@try {
    [mutex lock];
    // do non-trivial stuff
} 
@finally {
    [mutex unlock];
}
  

Это кажется разумным (и распространенным в Java), но я не видел, чтобы какой-либо код Cocoa делал это.

Следует ли использовать эту идиому? Почему или почему нет?

Ответ №1:

Чтобы гарантировать, что блокировка всегда снимается, всегда ли следует использовать следующую идиому?

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

Следует ли использовать эту идиому? Почему или почему нет?

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

  • Пример 1: Когда блокировка уничтожается (во dealloc время ), попытка ее уничтожения завершится неудачей, поскольку она все еще заблокирована. Не определено, продолжает ли реализация уничтожать блокировку или игнорирует ошибку (я бы предположил, что она будет сохраняться, что означает, что она никогда не завершится dealloc ).

  • Пример 2. Когда он заблокирован из другого потока (или того же потока, если не реентерабельный), вы никогда не получите блокировку, и в результате может возникнуть другая ошибка, взаимоблокировка или исключение. Реализация также может (в конечном итоге) продолжаться без получения блокировки. Все, что гарантировано, — это ведение журнала при обнаружении ошибки.

pthread_mutex es и зависящие от них реализации могут вести себя не очень корректно, если у вас такой дисбаланс блокировки; это всегда возвращается к ошибке программиста.

Правильная и защитная блокировка в чистом objc и c не очень хороша. Идиома Java верна и в равной степени применима к API Foundation. Причина, по которой вы этого не видите, может заключаться в том, что исключения являются менее популярным / используемым механизмом обработки ошибок в API Cocoa и зависящих от них программах (по сравнению с Java). см. Также Примечание Bavarious в комментариях

Комментарии:

1. Стоит упомянуть, что природа исключений в Cocoa довольно своеобразна по сравнению с другими языками / библиотеками. Исключения Cocoa (по большей части) возникают в ситуациях, когда проблему можно было бы предотвратить программно без обработчиков исключений (например, за пределы, проверяя границы перед чтением элемента массива) или проблема с трудом поддается восстановлению (например, неверный селектор, отправленный объекту, или соединение с оконным сервером было потеряно).

2. @Bavarious Да, хороший момент — мы печатали одновременно (я обновлял / расширял ответ, пока вы писали свой комментарий).

Ответ №2:

Нет.

Исключения используются только для ошибок программирования в Cocoa. Они не используются в ситуациях, когда ожидается, что программа восстановится.