-
Notifications
You must be signed in to change notification settings - Fork 62
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
Mutex for Kotlin/Common #508
base: native-thread-parking
Are you sure you want to change the base?
Conversation
bbrockbernd
commented
Feb 7, 2025
- A FIFO reentrant mutex for Kotlin/Common.
- Depends on Thread parking for Kotlin/Common #498 (Parking logic is under review there)
It would be better to set |
* Multiplatform mutex. | ||
* On native based on pthread system calls. | ||
* On JVM delegates to ReentrantLock. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is user-visible documentation, and so it must explain the contracts of the data structure. What is a mutex? What would an example of its usage look like? Is it reentrant? Is it fair? It should mention that it's unsuitable for async (suspend
) code, blocks the thread, and is only suitable for low-level technical work.
The same goes for every function in the file: all API entries need to be documented. When does each function return? When can it throw an exception? What does it do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have adjusted the docs, wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks!
* On JVM delegates to ReentrantLock. | ||
*/ | ||
expect class Mutex() { | ||
fun isLocked(): Boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if it turns out someone does need this function, they can do fun Mutex.isLocked() = if (tryLock()) { unlock(); true } else false
(right?), so including this function is purely a performance optimization for a performance problem that may not even exist. So, unless we know of some specific use cases for this function, let's not take on the extra commitment of including it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is correct. I have tried to keep the api similar to the coroutines mutex's api. But will remove it for now.
P.S. true and false should be swapped right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a second thought, this won't work if I am holding the lock myself since it is reentrant.
atomicfu/src/concurrentMain/kotlin/kotlinx/atomicfu/locks/Mutex.kt
Outdated
Show resolved
Hide resolved
atomicfu/src/concurrentMain/kotlin/kotlinx/atomicfu/locks/Mutex.kt
Outdated
Show resolved
Hide resolved
atomicfu/src/concurrentMain/kotlin/kotlinx/atomicfu/locks/Mutex.kt
Outdated
Show resolved
Hide resolved
atomicfu/src/jsAndWasmSharedMain/kotlin/kotlinx/atomicfu/locks/Mutex.jsAndWasmShared.kt
Show resolved
Hide resolved
atomicfu/src/concurrentMain/kotlin/kotlinx/atomicfu/locks/Mutex.kt
Outdated
Show resolved
Hide resolved
/** | ||
* Multiplatform mutex. | ||
* On native based on pthread system calls. | ||
* On JVM delegates to ReentrantLock. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem accurate, though? ReentrantLock
does get used in synchronized
and kotlinx.atomicfu.ReentrantLock
, but not in Mutex
, right?
If so, there seems to be some inconsistency: on the one hand, atomicfu.ReentrantLock
delegates to Java's ReentrantLock
, on the other, atomicfu.Mutex
doesn't, whereas on Native, atomicfu.ReentrantLock
and atomcifu.Mutex
are basically the same thing.
If we believe that our mutex is better, we should use it throughout; if we don't, we should use ReentrantLock
throughout. Are there measurements showing which one performs better?
…o ReentrantLock on JVM, inline and private funs where possible. Additionally removed legacy NativeNode.
public fun <init> (Ljava/util/concurrent/locks/ReentrantLock;)V | ||
public final fun getReentrantLock ()Ljava/util/concurrent/locks/ReentrantLock; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid exposing the ReentrantLock
constructor and accessor for now. What if we do implement our own mutex down the line that performs better?
* Multiplatform mutex. | ||
* On native based on pthread system calls. | ||
* On JVM delegates to ReentrantLock. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks!
* 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). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not true on the JVM, though? https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html#%3Cinit%3E() creates an unfair lock by default.