CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlinx--kotlinx-coroutines-core-iosx64

Kotlin coroutines library providing comprehensive asynchronous programming support with structured concurrency for iOS x64 platforms

Pending
Overview
Eval results
Files

synchronization.mddocs/

Synchronization

Non-blocking synchronization primitives including mutex and semaphore for coroutine coordination. These primitives provide thread-safe coordination without blocking OS threads.

Capabilities

Mutex

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
): T

Usage 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 1000

Semaphore

Counting 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): T

Usage 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()
}

Advanced Usage

Multiple Resource Access

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()
        }
    }
}

Timeout with Synchronization

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")
}

Fair vs Unfair Locking

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)
        }
    }
}

Best Practices

Resource Management

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
}

Avoiding Deadlocks

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
        }
    }
}

Performance Considerations

  • Mutex and Semaphore are lightweight and don't block OS threads
  • Use them instead of thread-blocking synchronization primitives
  • Consider using actors or channels for more complex coordination
  • Profile your application to ensure synchronization isn't a bottleneck

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-coroutines-core-iosx64

docs

channels.md

coroutine-builders.md

coroutine-management.md

dispatchers.md

error-handling.md

flow-api.md

index.md

select-expression.md

synchronization.md

tile.json