On K/N (single-threaded) the following coroutine d...
# coroutines
b
On K/N (single-threaded) the following coroutine does not execute anything, what am I missing?
Copy code
fun runPeriodicallyAsync(intervalMS: Long, action: () -> Unit): () -> Unit {
  val job = GlobalScope.launch {
    coroutineScope {
      while (true) {
        println("Executing")
        action()
        println("Delaying $intervalMS ms")
        delay(intervalMS)
      }
    }
  }
  println("Returning")
  return {
    println("Disposing")
    job.cancel()
  }
}
Does not execute anything as in: • "Executing" is never printed • "Delaying" is never printed • "Returning" IS printed
m
I think delay needs multi threaded coroutines to work. Try using
1.3.3-native-mt
version of coroutines-native
b
But in that case wouldn't it execute once before crashing anyways?
m
I have almost identical code but without
coroutineScope
block inside
launch
and it works fine. Also my
action
block is marked with
suspend
keyword.
a
@Big Chungus why are you cancelling the job
b
I'm not, I'm returning a function that's when invoked will cancel it. As in "unsubscribe" function
a
global scope does not wait, as long as main function has returned(came to end point) all daemon threads are destroyed and cancelled, you need something in main thread so that global scope coroutine will run in back.
b
@Animesh Sahu I'm not, have a look at return type, it's a function.
Also "Disposing" is not printed
a
Ohh, i just didnt saw lambda
👍 1
b
@mzgreen can you share your code? also which version of coroutines are you using?
a
Hey it just works fine in my case
b
Which version of coroutines?
m
I’m using 1.3.3-native-mt because with other versions (not supporting multithreading) delay didn’t work . My code looks like this:
Copy code
GlobalScope.launch {
    while(isActive) {
        action() 
        delay(1000)
    }
}
Where
action
is:
Copy code
suspended fun action() { 
    // some work
}
a
1.3.2
b
Odd... 😕
a
Did you tried adding some sleep calls(in main function) for checking if main exits before coroutine is launched
b
It certainly does not as it's a GUI app
a
ohh
might be a bug
b
the issue seems to be related to content switching
a
Or specifically for K/N(i didnt tested), K/JVM works fine
b
K/JVM has entirely different memory model 😄 Most of the K/JVM stuff will not work on K/N
m
I run my code on K/N specifically on iOS. Have you tried printing something before and after GlobalScope.launch block?
b
Yes, both prints
m
I would try to simplify the code and check if it works and when you get it working you can start building your desired solution one part at a time and see what exactly breaks it
u
Does it work without `coroutineScope`for you, as @mzgreen reported? Then we'd have something to look into :-)
b
No, neither worked.
In the end I scrapped that approach and managed to get what i need with this:
Copy code
@SharedImmutable
val engineRunning = AtomicInt(0)
@SharedImmutable
private val engineDispatcher = newSingleThreadContext("engine")

actual fun startEngine(appConfigStore: AppConfigStoreImpl, universeStore: UniverseStoreImpl) {
  if (engineRunning.value == 0) {
    engineRunning.increment()
    val stateChannel = Channel<AppConfigState>().freeze()
    val dispatchChannel = Channel<Int>()
    val universeStorePtr = StableRef.create(universeStore).freeze()
    GlobalScope.launch {
      for (action in dispatchChannel) {
        universeStorePtr.get().dispatch(UniverseAction.Tick)
      }
    }
    appConfigStore.subscribe {
      GlobalScope.launch(engineDispatcher) { stateChannel.send(it.freeze()) }
    }
    GlobalScope.launch(engineDispatcher) {
      var state = AppConfigState()
      while (isActive) {
        if (!stateChannel.isEmpty) {
          state = stateChannel.receive()
        }
        if (state.running) {
          dispatchChannel.send(0)
        }
        delay((1000 / state.fps).toLong())
      }
    }
  } else {
    println("engine already running")
  }
}
j
Could it be that
job
is being garbage collected once you return from
runPeriodicallyAsync
?
b
Well the returned lambda keeps reference to it
j
Yeah, you're right. I just verified that that a lambda does keep a reference.