TSemaphore
TSemaphore is the transactional Semaphore.
Semaphores are mostly used to limit concurrent access to resources by how many permits it can give out.
Creating a TSemaphore
A TSemaphore is created by using either TSemaphore.new outside of transactions or STM.newTSem inside a transaction. Both of these methods throw if the supplied initial value is negative.
Acquiring one or more permits
import arrow.fx.stm.TSemaphore
import arrow.fx.stm.atomically
suspend fun main() {
//sampleStart
val tsem = TSemaphore.new(5)
atomically {
// acquire one permit
tsem.acquire()
// acquire 3 permits
tsem.acquire(3)
}
//sampleEnd
println("Permits remaining ${atomically { tsem.available() }}")
}
Should there be not enough permits the transaction will retry and wait until there are enough permits available again. STM.tryAcquire can be used to avoid this behaviour as it returns whether or not acquisition was successful.
import arrow.fx.stm.TSemaphore
import arrow.fx.stm.atomically
suspend fun main() {
//sampleStart
val tsem = TSemaphore.new(0)
val result = atomically {
tsem.tryAcquire()
}
//sampleEnd
println("Result $result")
println("Permits remaining ${atomically { tsem.available() }}")
}
Release permits after use:
Permits can be released again using STM.release:
import arrow.fx.stm.TSemaphore
import arrow.fx.stm.atomically
suspend fun main() {
//sampleStart
val tsem = TSemaphore.new(5)
atomically {
tsem.release()
}
//sampleEnd
println("Permits remaining ${atomically { tsem.available() }}")
}
As you can see there is no upper limit enforced when releasing. You are free to release more or less permits than you have taken, but that may invalidate some other implicit rules so doing so is not advised.
STM.release will throw if given a negative number of permits.
Reading how many permits are currently available
import arrow.fx.stm.TSemaphore
import arrow.fx.stm.atomically
suspend fun main() {
//sampleStart
val tsem = TSemaphore.new(5)
val result = atomically {
tsem.available()
}
//sampleEnd
println("Result $result")
println("Permits remaining ${atomically { tsem.available() }}")
}