Продолжаю изучать многопоточность в
Rust и сравниваю со
Swift. Сегодня хочу поговорить про семафор - инструмент, который позволяет координировать одновременный доступ нескольких потоков к общим данным или ресурсам.
Принцип работы семафора основан на счетчике с атомарными операциями. Поток, который хочет получить доступ к ресурсу, вызывает операцию ожидания. Если значение счетчика больше нуля, оно уменьшается и поток продолжает работу. Когда значение достигает нуля, следующие потоки блокируются до тех пор, пока один из работающих потоков не освободит ресурс и не увеличит значение счетчика.
Rust с Semaphore:
use std::sync::Semaphore;
use std::thread;
let semaphore = Arc::new(Semaphore::new(2)); // Максимум 2 потока
for i in 0..5 {
let semaphore = Arc::clone(&semaphore);
thread::spawn(move || {
let _guard = semaphore.access(); // Захватываем семафор
println!("Задача {} выполняется", i);
thread::sleep(Duration::from_secs(1));
}); // Семафор освобождается автоматически при выходе из области видимости
}
Swift с DispatchSemaphore:
let semaphore = DispatchSemaphore(value: 2) // Максимум 2 потока
for i in 0..<5 {
DispatchQueue.global().async {
semaphore.wait() // Захватываем семафор
print("Задача \(i) выполняется")
Thread.sleep(forTimeInterval: 1)
semaphore.signal() // Освобождаем семафор
}
}
// Риск deadlock'а если забыть вызвать signal()
В
Swift семафор требует ручного вызова
wait()/
signal(), что может привести к
deadlock если забыть вызвать
signal(). В
Rust семафор освобождается автоматическим при выходе из области видимости.
В
Rust более безопасный подход, но
Swift дает больше контроля для опытных разработчиков.