Sobes.tech
Middle
132
questionbank

В чем разница между семафором и мьютексом?

AI答案

sobes.tech AI

Семафор — это обобщенный механизм синхронизации, используемый для управления доступом к ограниченному ресурсу несколькими конкурирующими потоками. Он поддерживает целочисленное значение, которое уменьшается при захвате ресурса и увеличивается при освобождении. Если значение семафора равно нулю, попытка захвата блокирует поток до тех пор, пока другой поток не освободит ресурс. Может использоваться для ограничения количества одновременно работающих потоков.

Мьютекс (мьютеx-exclusion — взаимное исключение) — это бинарный семафор, который может находиться либо в заблокированном, либо в разблокированном состоянии. Он используется для защиты критической секции кода от одновременного доступа нескольких потоков. Только один поток может захватить мьютекс в любой момент времени. Поток, захвативший мьютекс, не может быть прерван другим потоком, пытающимся захватить тот же мьютекс. Если попытаться захватить заблокированный мьютекс, поток будет блокирован до его освобождения.

Ключевые различия:

Характеристика Семафор Мьютекс
Тип Обобщенный механизм синхронизации Бинарный семафор (частный случай семафора)
Значение Целочисленное (>= 0) Бинарное (0 или 1)
Назначение Управление доступом к ресурсам, ограничение потоков Защита критических секций, взаимное исключение
Владелец Может не иметь владельца Всегда имеет владельца (поток, захвативший его)
Использование в iOS DispatchSemaphore Часто реализуется через DispatchQueue.sync или NSRecursiveLock в некоторых сценариях

Пример использования мьютекса для защиты критической секции:

// В контексте GCD (Grand Central Dispatch)
let serialQueue = DispatchQueue(label: "com.example.criticalSection")

serialQueue.sync {
    // Критическая секция кода
    // Только один поток может быть здесь в любой момент времени
}

Пример использования семафора для ограничения параллельных задач:

// В контексте GCD (Grand Central Dispatch)
let semaphore = DispatchSemaphore(value: 3) // Разрешаем 3 параллельные задачи

DispatchQueue.global().async {
    semaphore.wait() // Уменьшаем значение семафора на 1. Блокируется, если значение = 0.

    // Код задачи, выполняемой параллельно
    print("Задача выполняется")

    Thread.sleep(forTimeInterval: 1) // Имитация работы

    semaphore.signal() // Увеличиваем значение семафора на 1. Разблокирует ожидающий поток, если таковые есть.
    print("Задача завершена")
}

// Можно запустить несколько таких блоков. Только 3 будут выполняться одновременно.