Семафор в Kotlin
Семафор считает, сколько корутин одновременно
могут войти в участок. У Semaphore из
kotlinx.coroutines.sync задают начальное
число разрешений в конструкторе.
Функция acquire забирает одно разрешение и при
нуле приостанавливает корутину. Функция release
возвращает разрешение ожидающим. Снятие в
finally повторяет правило замка:
import kotlinx.coroutines.sync.Semaphore
val lane = Semaphore(2)
suspend fun enter() {
lane.acquire()
try {
println("inside")
} finally {
lane.release()
}
}
Два разрешения означают, что третья корутина
останется ждать, пока кто-то не вызовет
release. Три задачи по очереди проходят
короткий участок:
import kotlinx.coroutines.delay
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Semaphore
fun main() {
runBlocking {
val lane = Semaphore(2)
val jobs = List(3) { id ->
launch {
lane.acquire()
try {
println("start $id")
delay(50)
println("end $id")
} finally {
lane.release()
}
}
}
joinAll(*jobs.toTypedArray())
}
}
Счетчик активных гостей удобно держать рядом с
семафором: под acquire увеличивают,
под release уменьшают. Так видно,
что одновременно внутри не больше двух:
import kotlinx.coroutines.sync.Semaphore
class Hall(private val lane: Semaphore = Semaphore(2)) {
private var inside = 0
suspend fun visit() {
lane.acquire()
try {
inside++
println(inside)
} finally {
inside--
lane.release()
}
}
}
Семафор на 2 разрешения. Четыре
корутины печатают метку входа, ждут
30 мс и печатают выход, каждый
раз забирая и возвращая разрешение в
finally.
Класс Booth с семафором на два
места и методом serve. Три
запуска по очереди вызывают обслуживание
и выводят строку "ok" внутри
участка.