https://kotlinlang.org logo
#coroutines
Title
# coroutines
i

iseki

10/28/2023, 8:09 PM
I have a question, why we don't allow semaphore
acquired > permits
? I'm trying to write a test case, which require to wait some sub-coroutine running to a point. So I'm trying:
Copy code
kotlin
runBlocking{
  val sem = Semaphore(1, 3)
  repeat(3){
    launch{ sem.release() }
  }
  sem.acquire()
}
Especially in Java it's easy to impl. Just
java.util.concurrent.Semaphore(-3)
.
m

Mikhail

10/29/2023, 8:56 AM
I don't catch goal of your code. What behavior do you expect?
i

iseki

10/29/2023, 2:38 PM
Kotlin doesn't allow the acquiredPermits larger than permits
s

Szymon Jeziorski

10/30/2023, 10:36 AM
Semaphore in Kotlin Coroutines is different as its contract defines exact, fixed number of simultaneous permits available, which cannot be changed in runtime (excluding hacky ways as Reflection of course). Having such declaration:
Copy code
val semaphore = kotlinx.coroutines.sync.Semaphore(5)
You are sure that
semaphore
object allows exactly 5 available permits, and whatever happens, this number will not change in runtime, and with this information you can use it for example to limit effective parallelism. And you can do it without worrying of its behavior changing due to alteration of total available permits (intentional or not). Java's version of Semaphore does not guarantee any such contract, the number of total available permits can change in runtime fairly easily.
Copy code
val semaphore = java.util.concurrent.Semaphore(3) // 3 initial permits available
semaphore.release() // 4 permits available
Looking at the above Java's example: initially created Semaphore has 3 available permits and 0 permits acquired. When we call
release
line after, it would be perfectly logical to me, to actually release something, that something being already acquired permit. What actually happens is the internal counter of available permits being incremented, resulting in increase of the number of total available permits. For Kotlin's Semaphore, calling
release
in such case would result in
IllegalStateException
- there are no permits acquired, so it makes sense that there's nothing to release. In the same way, it wouldn't be logical for Kotlin's Semaphore to held negative number of acquired permits, or have number of acquired permits larger than number of total permits. Kotlin's version of Semaphore has its validations underneath, enforcing usage correct to its contract (which to me is a great thing), while Java however, has much looser approach and leaves it to user, to use the API correctly. Quoting part of
java.util.concurrent.Semaphore.release
documentation for example:
Copy code
There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire. Correct usage of a semaphore is established by programming convention in the application.
With all that said, in your case I would just use different tools to achieve what you need (bigger context would be appreciated here, in case you need some help with it)
5 Views