kotlinconcurrencykotlin-coroutinescoroutine

How to force 2 coroutines never run simultaneously


In this code:

private suspend fun doSthSingleThreaded(){
    coroutineScope {
        //Coroutine 1
        launch {
            //do sth that will suspend
        }
        //Coroutine 2
        launch {
            //Do sth else that will suspend too
        }
    }
}

Is there a way that I can make these 2 Coroutines behave like they are sharing the underlying thread? this is how I want it to work ( I want to adjust the code in a way that they both use threadA):

EDIT: This is Y I want to do this: I have a SharedFlow that is somehow a single source of truth for all the data I receive from a serial port.

val hotFlow = SharedFlow<String> //buffer = ALot, replay = 0

Any time I write anything to that port I read it's answer from here. like this:

port.writeSth()
val answer = hotFlow.first {it == "OK" || it == "ERROR"}
if (answer == "OK") return
//process error

The problem with the code above (with replay = 0) is that HotFlow sometimes returns a response and then returns sth else so quickly that I am not able catch my answer!

Why replay = 0? All the different commands that I write to this port have the answer "OK" or "ERROR", and the port does not return anything that says what command this answer belongs to. So if replay != 0:

port.writeSth()
val portCache = hotFlow.replay
//Now how do I know if the last item is my answer or I should still wait?

so I thought maybe I can:

launch {
    val answer = hotFlow.first{it == "OK" || it == "ERROR" }
    //process answer
}
launch {
    port.writeSth()
}

order of execution:

  1. Collect everything from port and suspend
  2. Write something
  3. First suspended coroutine definitely catches the answer

Solution

  • You can get a single thread bound coroutine dispatcher with newSingleThreadContext, but please be wary:

    A dedicated thread is a very expensive resource. In a real application it must be either released, when no longer needed, using the close function, or stored in a top-level variable and reused throughout the application.

    If instead you only need to limit parallelism you can use limitedParallelism instead: Dispatchers.Default.limitedParallelism(1). This will not guarantee that the coroutines will always use the same thread, only that at most one coroutine is executed at the same time.

    private suspend fun doSthSingleThreaded() {
        val confined = newSingleThreadContext("My Thread")
    //    or
    //    val confined = Dispatchers.Default.limitedParallelism(1)
        withContext(confined) {
            //Coroutine 1
            launch {
                //do sth that will suspend
            }
            //Coroutine 2
            launch {
                //Do sth else that will suspend too
            }        
        }
    }