How to achieve this behavior with Coroutines?

In C# you could achieve something like this:

  Console.WriteLine("Thread name " + Thread.CurrentThread.Name); // Main
            var p = await DbHandler.Database.Accounts.Find(x => x.Id == id).FirstOrDefaultAsync();
            player.Name = p.Name; // player.Name call native sync code and works in main
            Console.WriteLine("Thread name2 "+Thread.CurrentThread.Name); // Main

I tried to do something equivalent in kotlin:

IdenCoroutine.launch(Dispatchers.Unconfined) {

    println("Thread Name: ${Thread.currentThread().name}") // this is main

    val user = getUser() // non-blocking await
	
	p.name = user.name // p.name calls a native jni function that fails when executed in a thread other than main.

    println("Thread name 2: " + "current thread is ${Thread.currentThread().name}") // this is DefaultDispatcher-worker-1 and fails p.name
}

suspend fun getUser() = withContext(Dispatchers.IO) {
	// get user from db
}

But it fails because the coroutine sends p.name to another thread.

So the question is how can I replicate what I was doing in C# with Kotlin Coroutines?

Do you mean to jump to the main thread after returning from the getUser()? If so then why do you use Dispatchers.Unconfined instead of Dispatchers.Main?

Because Dispatchers.Main is only available on Android and my project is a backend.

Hmm, ok, so what is this “main” thread? Is it already used by some coroutine dispatcher? if not, do you have control on how it is created or maybe it is provided to you by some kind of library? If you don’t control it, is it some kind of an event-loop or is it just “some” thread?

I ask these questions, because coroutines need to have a way to schedule a task to be performed on a specific thread. Normally, you can’t just tell some thread to do something. Such thread has to cooperate, it has to provide a way to schedule tasks to it, so It has to be some kind of an event-loop - either operated by a coroutine dispatcher already or by some other library.

The main thread in my application would be the one created with JNI_CreateJavaVM.

I don’t know how this C# code works exactly, but I believe it is technically impossible to execute something using just “any” thread, then release this thread to do something else and then jump back to it again. It is only possible if either the thread is managed by a concurrency framework of some sort (coroutine dispatcher, executor, our own event-loop implementation, etc.) or if we don’t really release the thread, but occupy it all the time by blocking it.

My guess is that this main thread of C# is a special thread that is managed by async/await machinery to make possible to jump to it.

Anyway, I don’t know what is your specific case, but you can start a thread, make it managed by coroutines and then use this thread as your “main” thread:

fun main() {
    IdenCoroutine.launch(myMainDispatcher) {
        println("Thread Name: ${Thread.currentThread().name}") // my-main-thread
        val user = getUser() // non-blocking await
        println("Thread name 2: " + "current thread is ${Thread.currentThread().name}") // my-main-thread
    }
}

val myMainDispatcher = Executors.newSingleThreadExecutor {
    thread(name = "my-main-thread", start = false, block = it::run)
}.asCoroutineDispatcher()

If you have to use already existing thread then you can make it “managed” by invoking runBlocking(), then block it forever and write your whole code inside this runBlocking() call. But this is probably not the usual use case for runBlocking() and there may be some drawbacks.

I realized that the API I use has an event loop called “onProcessTick”, now my only question would be how I could adjust this to handle it as a Dispatcher in Coroutines.

// IdenCoroutine == GlobalScope
        IdenCoroutine.launch(Dispatchers.IO) {
            // this is DefaultDispatcher-worker-1
            ServerAPI.executeOnMainThread {
                // Works, this is main thread
            }
        }

API code:

private val mainThreadTasks = ConcurrentLinkedQueue<() -> Unit>()

override fun onProcessTick() { // callback JNI
        do {
            tryAndCatch {
                val task = mainThreadTasks.poll() ?: return
                task.invoke()
            }
        } while (true)
    }

override fun executeOnMainThread(action: () -> Unit) {
        if (serverService.isOnMainThread()) {
            action()
        } else {
            mainThreadTasks.add(action)
        }
    }

Wrap executeOnMainThread in an Executor and use Executor.asCoroutineDispatcher()

Thanks I did what you told me and it worked. Is there a way to override Dispatchers.Main to work with a custom dispatcher?

Dispatchers.Main docs say you can with ServiceLoader