Kotlin coroutines library providing comprehensive asynchronous programming support with structured concurrency for iOS x64 platforms
—
Non-blocking synchronization primitives including mutex and semaphore for coroutine coordination. These primitives provide thread-safe coordination without blocking OS threads.
Non-reentrant mutual exclusion primitive for protecting shared resources.
/**
* Mutual exclusion primitive that is not reentrant
*/
interface Mutex {
/** True if mutex is currently locked */
val isLocked: Boolean
/** Lock the mutex, suspending if already locked */
suspend fun lock(owner: Any? = null)
/** Unlock the mutex */
fun unlock(owner: Any? = null)
/** Try to lock immediately without suspending */
fun tryLock(owner: Any? = null): Boolean
/** Check if current owner holds the lock */
fun holdsLock(owner: Any): Boolean
}
/**
* Create a new Mutex
* @param locked initial lock state
*/
fun Mutex(locked: Boolean = false): Mutex
/**
* Execute block with mutex locked
*/
suspend fun <T> Mutex.withLock(
owner: Any? = null,
action: suspend () -> T
): TUsage Examples:
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
class Counter {
private var count = 0
private val mutex = Mutex()
suspend fun increment() = mutex.withLock {
count++
}
suspend fun get() = mutex.withLock {
count
}
suspend fun decrement() = mutex.withLock {
count--
}
}
// Usage
val counter = Counter()
// Launch multiple coroutines
repeat(1000) {
launch {
counter.increment()
}
}
println("Final count: ${counter.get()}") // Always 1000Counting semaphore for controlling access to a limited number of resources.
/**
* Counting semaphore for resource access control
*/
interface Semaphore {
/** Number of permits currently available */
val availablePermits: Int
/** Acquire a permit, suspending if none available */
suspend fun acquire()
/** Release a permit */
fun release()
/** Try to acquire a permit immediately without suspending */
fun tryAcquire(): Boolean
}
/**
* Create a new Semaphore
* @param permits number of permits available
* @param acquiredPermits number of permits already acquired
*/
fun Semaphore(
permits: Int,
acquiredPermits: Int = 0
): Semaphore
/**
* Execute block with semaphore permit
*/
suspend fun <T> Semaphore.withPermit(action: suspend () -> T): TUsage Examples:
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
// Limit concurrent network requests to 3
val networkSemaphore = Semaphore(3)
suspend fun fetchData(url: String): String {
return networkSemaphore.withPermit {
// Only 3 coroutines can execute this block concurrently
httpClient.get(url)
}
}
// Database connection pool
class DatabasePool(private val maxConnections: Int = 10) {
private val semaphore = Semaphore(maxConnections)
private val connections = mutableListOf<Connection>()
suspend fun <T> useConnection(block: suspend (Connection) -> T): T {
return semaphore.withPermit {
val connection = getConnection()
try {
block(connection)
} finally {
releaseConnection(connection)
}
}
}
}
// Rate limiting example
class RateLimiter(requestsPerSecond: Int) {
private val semaphore = Semaphore(requestsPerSecond)
init {
// Replenish permits every second
CoroutineScope(Dispatchers.Default).launch {
while (true) {
delay(1000 / requestsPerSecond)
if (semaphore.availablePermits < requestsPerSecond) {
semaphore.release()
}
}
}
}
suspend fun acquire() = semaphore.acquire()
}Using multiple synchronization primitives together.
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
class SharedResource {
private val readWriteMutex = Mutex()
private val readers = Semaphore(5) // Allow up to 5 concurrent readers
private var readerCount = 0
suspend fun read(block: suspend () -> Unit) {
readers.withPermit {
readWriteMutex.withLock {
readerCount++
if (readerCount == 1) {
// First reader, acquire write lock
}
}
try {
block() // Reading happens here
} finally {
readWriteMutex.withLock {
readerCount--
if (readerCount == 0) {
// Last reader, release write lock
}
}
}
}
}
suspend fun write(block: suspend () -> Unit) {
readWriteMutex.withLock {
// Exclusive access for writing
block()
}
}
}Using synchronization primitives with timeouts.
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
suspend fun tryLockWithTimeout(mutex: Mutex, timeoutMs: Long): Boolean {
return try {
withTimeout(timeoutMs) {
mutex.lock()
true
}
} catch (e: TimeoutCancellationException) {
false
}
}
suspend fun tryAcquireWithTimeout(semaphore: Semaphore, timeoutMs: Long): Boolean {
return try {
withTimeout(timeoutMs) {
semaphore.acquire()
true
}
} catch (e: TimeoutCancellationException) {
false
}
}
// Usage
val mutex = Mutex()
if (tryLockWithTimeout(mutex, 1000)) {
try {
// Critical section
performCriticalOperation()
} finally {
mutex.unlock()
}
} else {
// Handle timeout
println("Could not acquire lock within timeout")
}Mutex and Semaphore in kotlinx.coroutines provide fair locking by default.
// Fair locking - coroutines acquire locks in FIFO order
val fairMutex = Mutex()
val fairSemaphore = Semaphore(1)
// Multiple coroutines waiting for the same resource
// will acquire it in the order they requested it
repeat(10) { i ->
launch {
fairMutex.withLock {
println("Coroutine $i acquired lock")
delay(100)
}
}
}Always use withLock and withPermit to ensure proper cleanup:
// Good - automatic cleanup
mutex.withLock {
// Critical section
riskyOperation()
}
// Avoid - manual lock management
mutex.lock()
try {
riskyOperation()
} finally {
mutex.unlock() // Easy to forget or skip on exception
}Be careful with multiple locks to avoid deadlocks:
// Potential deadlock - different lock ordering
suspend fun transfer1(from: Account, to: Account, amount: Int) {
from.mutex.withLock {
to.mutex.withLock {
from.balance -= amount
to.balance += amount
}
}
}
suspend fun transfer2(from: Account, to: Account, amount: Int) {
to.mutex.withLock { // Different order - potential deadlock!
from.mutex.withLock {
from.balance -= amount
to.balance += amount
}
}
}
// Solution - consistent lock ordering
suspend fun safeTransfer(from: Account, to: Account, amount: Int) {
val (first, second) = if (from.id < to.id) from to to else to to from
first.mutex.withLock {
second.mutex.withLock {
from.balance -= amount
to.balance += amount
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-coroutines-core-iosx64