Skip to content

Mutex for Kotlin/Common #508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: native-thread-parking
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions atomicfu/api/atomicfu.api
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,15 @@ public final class kotlinx/atomicfu/locks/ParkingSupport {
public final fun unpark (Ljava/lang/Thread;)V
}

public final class kotlinx/atomicfu/locks/SynchronousMutex {
public fun <init> ()V
public final fun lock ()V
public final fun tryLock ()Z
public final fun tryLock-LRDsOJo (J)Z
public final fun unlock ()V
}

public final class kotlinx/atomicfu/locks/SynchronousMutexKt {
public static final fun withLock (Lkotlinx/atomicfu/locks/SynchronousMutex;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
}

1 change: 1 addition & 0 deletions atomicfu/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ kotlin {

jvmTest {
dependencies {
implementation("org.jetbrains.kotlinx:lincheck:2.38")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-test")
implementation("org.jetbrains.kotlin:kotlin-test-junit")
Expand Down

This file was deleted.

This file was deleted.

10 changes: 0 additions & 10 deletions atomicfu/src/appleMain/kotlin/kotlinx/atomicfu/locks/ThreadId.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package kotlinx.atomicfu.locks

import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.time.Duration

/**
* Mutual exclusion for Kotlin Multiplatform.
*
* It can protect a shared resource or critical section from multiple thread accesses.
* Threads can acquire the lock by calling [lock] and release the lock by calling [unlock].
*
* When a thread calls [lock] while another thread is locked, it will suspend until the lock is released.
* When multiple threads are waiting for the lock, they will acquire it in a fair order (first in first out).
* On JVM, a [lock] call can skip the queue if it happens in between a thread releasing and the first in queue acquiring.
*
* It is reentrant, meaning the lock holding thread can call [lock] multiple times without suspending.
* To release the lock (after multiple [lock] calls) an equal number of [unlock] calls are required.
*
* This Mutex should not be used in combination with coroutines and `suspend` functions
* as it blocks the waiting thread.
* Use the `Mutex` from the coroutines library instead.
*
* ```Kotlin
* mutex.withLock {
* // Critical section only executed by
* // one thread at a time.
* }
* ```
*/
expect class SynchronousMutex() {
/**
* Tries to lock this mutex, returning `false` if this mutex is already locked.
*
* It is recommended to use [withLock] for safety reasons, so that the acquired lock is always
* released at the end of your critical section, and [unlock] is never invoked before a successful
* lock acquisition.
*
* (JVM only) this call can potentially skip line.
*/
fun tryLock(): Boolean

/**
* Tries to lock this mutex within the given [timeout] period,
* returning `false` if the duration passed without locking.
*
* Note: when [tryLock] succeeds the lock needs to be released by [unlock].
* When [tryLock] does not succeed the lock does not have to be released.
*
* (JVM only) throws Interrupted exception when thread is interrupted while waiting for lock.
*/
fun tryLock(timeout: Duration): Boolean

/**
* Locks the mutex, suspends the thread until the lock is acquired.
*
* It is recommended to use [withLock] for safety reasons, so that the acquired lock is always
* released at the end of your critical section, and [unlock] is never invoked before a successful
* lock acquisition.
*/
fun lock()

/**
* Releases the lock.
* Throws [IllegalStateException] when the current thread is not holding the lock.
*
* It is recommended to use [withLock] for safety reasons, so that the acquired lock is always
* released at the end of the critical section, and [unlock] is never invoked before a successful
* lock acquisition.
*/
fun unlock()
}

/**
* Executes the given code [block] under this mutex's lock.
*
* @return result of [block]
*/
@OptIn(ExperimentalContracts::class)
inline fun <T> SynchronousMutex.withLock(block: () -> T): T {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
lock()
return try {
block()
} finally {
unlock()
}
}
Loading