Skip to content
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

doc: clarify ReentrantLock should not be used with coroutines #518

Open
bcmedeiros opened this issue Feb 19, 2025 · 0 comments
Open

doc: clarify ReentrantLock should not be used with coroutines #518

bcmedeiros opened this issue Feb 19, 2025 · 0 comments

Comments

@bcmedeiros
Copy link

bcmedeiros commented Feb 19, 2025

I have some code like this:

    routing {
        route("/api/v1") {
            put("/e/{id}") {
                lock.withLock {
                    delay(1) // calling delay makes the issue more likely to happen
                    taskWhichSuspends()
                }
                call.respond(HttpStatusCode.OK)
            }
    // ...

I inadvertently implemented lock in the code above as:

private val lock = reentrantLock()

when I should have used

private val lock = Mutex()

The distinction is made very clear in https://kotlinlang.org/docs/shared-mutable-state-and-concurrency.html#mutual-exclusion, but I had atomicfu in my classpath and it seems intuitive to just add the reentrantLock().

This caused my app to fail with an exception like the one below:

[ERROR] (io.ktor.server.Application): Unhandled: PUT - /api/v1/e/01951eef-4479-73a0-ba85-167a286c2689. Cause: kotlin.IllegalArgumentException: Thin lock may be only released by the owner thread, expected: 125286194079424, real: 125286185686720
    at 0   main-app.kexe                   0x79ae6d           kfun:kotlin.Throwable#<init>(kotlin.String?){} + 93 
    at 1   main-app.kexe                   0x7956f9           kfun:kotlin.Exception#<init>(kotlin.String?){} + 89 
    at 2   main-app.kexe                   0x7958a9           kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 89 
    at 3   main-app.kexe                   0x795b69           kfun:kotlin.IllegalArgumentException#<init>(kotlin.String?){} + 89 
    at 4   main-app.kexe                   0xb89e0d           kfun:io.ktor.utils.io.locks.SynchronizedObject#unlock(){} + 1565 
    at 5   main-app.kexe                   0x6b9027           kfun:app.s.routes$lambda$5$lambda$4$lambda$0COROUTINE$0.invokeSuspend#internal + 8711 

After reading the shared mutable state docs mentioned above, I don't think atomicfu is at fault, reentrantLock() is not supposed to work with coroutines, but I really think we could mention this in the docs in this project, and point people towards the Mutex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

1 participant