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

Что такое семафор?

1.3 Junior🔥 21 комментариев
#Многопоточность и асинхронность

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

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

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

Что такое семафор?

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

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

Типы семафоров

В программировании обычно выделяют два типа:

  • Бинарный семафор: счетчик может принимать только значения 0 или 1. Используется как мьютекс (mutex) для защиты критической секции — только один поток может одновременно работать с ресурсом.
  • Счетный семафор: счетчик может быть любым положительным целым числом. Используется для ограничения количества потоков, которые могут одновременно выполнять определенную операцию (например, не более 5 сетевых запросов одновременно).

Семафоры в iOS / Swift

В Swift (особенно при использовании GCD — Grand Central Dispatch) семафоры реализуются через класс DispatchSemaphore.

Основные методы DispatchSemaphore:

  • init(value: Int) — создает семафор с начальным значением счетчика.
  • wait() — уменьшает счетчик. Если счетчик меньше нуля, поток блокируется.
  • signal() — увеличивает счетчик и, если были заблокированные потоки, разблокирует один из них.

Пример использования в Swift

Пример 1: Бинарный семафор (защита критической секции)

import Foundation

let semaphore = DispatchSemaphore(value: 1)
var sharedResource = 0

DispatchQueue.concurrentPerform(iterations: 10) { index in
    semaphore.wait() // Захватываем семафор
    // Критическая секция — доступ к общему ресурсу
    sharedResource += 1
    print("Поток \(index): sharedResource = \(sharedResource)")
    semaphore.signal() // Освобождаем семафор
}

Пример 2: Счетный семафор (ограничение одновременных задач)

import Foundation

// Ограничиваем одновременные сетевые запросы до 3
let requestSemaphore = DispatchSemaphore(value: 3)

for i in 1...10 {
    DispatchQueue.global().async {
        requestSemaphore.wait() // Если уже 3 запроса, ждем
        
        // Имитация сетевого запроса
        print("Запрос \(i) начался")
        sleep(UInt32.random(in: 1...3))
        print("Запрос \(i) завершился")
        
        requestSemaphore.signal() // Освобождаем место для нового запроса
    }
}

Ключевые различия семафора и мьютекса

Хотя бинарный семафор похож на мьютекс, есть важные различия:

  • Семафор не имеет концепции "владельца". Любой поток может вызвать signal(), даже если он не вызывал wait().
  • Мьютекс (например, NSLock или pthread_mutex_t) обычно требует, чтобы тот же поток, который захватил мьютекс, освободил его. Это предотвращает ошибки логики.
  • Семафоры более универсальны и подходят для сигнализации между потоками (ожидание события), а мьютексы предназначены строго для защиты данных.

Применение семафоров в iOS разработке

  • Ограничение параллельных операций: например, при загрузке изображений или обработке большого количества данных.
  • Синхронизация между потоками: ожидание завершения одной задачи перед началом другой.
  • Реализация пула ресурсов: управление доступом к ограниченному набору объектов (например, соединениям с базой данных).

Опасности и лучшие практики

  • Deadlock: если семафор захватывается, но не освобождается, другие потоки могут заблокироваться навсегда.
  • Инверсия приоритетов: низкоприоритетный поток может блокировать высокоприоритетный, если захватил семафор.
  • Рекомендации: всегда освобождайте семафор в том же контексте, где захватили; используйте defer в Swift для гарантированного вызова signal().
semaphore.wait()
defer { semaphore.signal() } // Гарантированное освобождение при выходе из области видимости

// Работа с ресурсом

Семафоры — фундаментальный инструмент многопоточного программирования в iOS. Их правильное использование позволяет создавать эффективные, безопасные и масштабируемые приложения, избегая race conditions и чрезмерной нагрузки на систему.

Что такое семафор? | PrepBro