Как приостановить котлин сопрограммы до уведомления - PullRequest
1 голос
/ 29 марта 2019

Я бы хотел приостановить сопрограмму kotlin, пока метод не будет вызван извне, как старые методы Java object.wait () и object.notify ().Как мне это сделать?

Здесь: Правильно реализовать ожидание и уведомление в Kotlin - ответ, как реализовать это с потоками Kotlin (блокировка).И здесь: Приостановить сопрограмму до выполнения условия - это ответ, как это сделать с CompleteableDeferreds, но я не хочу каждый раз создавать новый экземпляр CompleteableDeferred.

Я делаюэто в настоящее время:

    var nextIndex = 0

    fun handleNext(): Boolean {
        if (nextIndex < apps.size) {
            //Do the actual work on apps[nextIndex]
            nextIndex++
        }
        //only execute again if nextIndex is a valid index
        return nextIndex < apps.size
    }

    handleNext()

    // The returned function will be called multiple times, which I would like to replace with something like notify()
    return ::handleNext

От: https://gitlab.com/SuperFreezZ/SuperFreezZ/blob/master/src/superfreeze/tool/android/backend/Freezer.kt#L69

Ответы [ 2 ]

4 голосов
/ 29 марта 2019

Каналы могут использоваться для этого (хотя они являются более общими):

Когда емкость 0 - это создает RendezvousChannel. Этот канал не имеет никакого буфера вообще. Элемент передается от отправителя к получателю только тогда, когда вызовы отправки и получения встречаются во времени (рандеву), поэтому отправка приостанавливается до тех пор, пока другая сопрограмма не вызовет получение и получение приостановит, пока другая сопрограмма не вызовет отправку.

Так создай

val channel = Channel<Unit>(0)

И используйте channel.receive() для object.wait() и channel.offer(Unit) для object.notify() (или send, если вы хотите подождать, пока другая сопрограмма receive s).

Для notifyAll вместо него можно использовать BroadcastChannel.

Вы, конечно, можете легко инкапсулировать это:

inline class Waiter(private val channel: Channel<Unit> = Channel<Unit>(0)) {

    suspend fun doWait() { channel.receive() }
    fun doNotify() { channel.offer(Unit) }
}
0 голосов
/ 29 марта 2019

Для этого можно использовать базовую функцию suspendCoroutine{..}, например,

class SuspendWait() {
  private lateinit var myCont: Continuation<Unit>
  suspend fun sleepAndWait() = suspendCoroutine<Unit>{ cont ->
    myCont = cont
  }

  fun resume() {
    val cont = myCont
    myCont = null
    cont.resume(Unit)
  }
}

Понятно, что в коде есть проблемы, например, Поле myCont не синхронизировано, ожидается, что sleepAndWait вызывается до resume и так далее, надеюсь, идея понятна.

Существует еще одно решение с классом Mutex из библиотеки kotlinx.coroutines.

class SuspendWait2 {
  private val mutex = Mutex(locaked = true)
  suspend fun sleepAndWait() = mutex.withLock{}
  fun resume() {
    mutex.unlock()
  }
}
...