Какие основные проблемы многопоточности
Что проверяют
Можете ли вы назвать проблемы по именам и объяснить, чем они отличаются друг от друга. Для iOS дополнительно интересует, как их избегают на практике.
Как отвечать
- гонка данных: два потока обращаются к одной памяти без синхронизации, и хотя бы один пишет. Результат зависит от порядка выполнения, и это неопределённое поведение, а не просто неверное число;
- состояние гонки: логическая ошибка порядка. Проверили условие, а к моменту действия оно перестало быть верным. Каждая операция может быть атомарной, а сценарий всё равно сломан;
- взаимная блокировка: два потока держат по ресурсу и ждут ресурс друг друга. Лечится единым порядком захвата;
- приоритетная инверсия: низкоприоритетная задача держит ресурс, нужный высокоприоритетной. В iOS от этого спасает передача качества обслуживания в GCD;
- голодание: поток никогда не получает ресурс;
- лишняя синхронизация: блокировки везде, параллелизма нет, зато есть накладные расходы.
Как их избегают в iOS: обновление интерфейса только на главной очереди; последовательная очередь или барьер в конкурентной вместо ручных блокировок; акторы в Swift Concurrency, которые изолируют состояние по построению, и проверка гонок компилятором в строгом режиме; для поиска остального есть Thread Sanitizer.
Где спотыкаются
Не различают гонку данных и состояние гонки.
Считают, что атомарные свойства делают класс потокобезопасным: каждое обращение атомарно, а пара операций уже нет.
Обновляют интерфейс из фоновой очереди и ловят плавающие падения.
Не знают про Thread Sanitizer и ищут гонки чтением кода.