Как синхронизировать сопрограмму? - PullRequest
5 голосов
/ 31 января 2020

Я пытаюсь убедиться, что эти два метода синхронизированы. Я заметил, что сопрограммы сложнее синхронизировать, чем потоки. Как я могу гарантировать, что если я позвоню start() затем stop(), мой код будет фактически остановлен в конце?

object Test {

    private val coroutine = CoroutineScope(Dispatchers.IO)

    @Synchronized
    fun start() {
        coroutine.launch {
            // some work
        }
    }

    @Synchronized
    fun stop() {
        coroutine.launch {
            // clean up then stop
        }
    }
}

Меня беспокоит то, что я звоню start(), затем stop(), но фактически сначала выполняется stop. Так что мой код продолжается, когда он должен был остановиться.

Ответы [ 4 ]

0 голосов
/ 31 января 2020

Если вы хотите отменить запущенное задание при вызове stop(), сохраните задание в поле:

object Test {

    private val coroutine = CoroutineScope(Dispatchers.IO)
    private var startedJob : Job? = null

    fun start() {
        startedJob = coroutine.launch {
            // some work
        }
    }

    fun stop() {
        runBlocking { startedJob?.cancelAndJoin() }
        coroutine.launch {
            // clean up then stop
        }
    }
}

-

Если ваш проблема заключается в вызывающей последовательности - сначала запустите, затем остановите - затем вы должны проверить и синхронизировать код, который вызывает ваш Test объект.

0 голосов
/ 31 января 2020

Вам просто нужно Job в CoroutineScope:

object Test {

    private val scope = CoroutineScope(Dispatchers.IO + Job())

    fun start() {
        scope.launch {
            // some work
        }
    }

    fun stop() {
        scope.cancel()
    }
}

0 голосов
/ 31 января 2020

Синхронизация или последовательное выполнение команд - это две разные вещи. Если вам нужно выполнить «start», а затем «stop», просто не создавайте новые сопрограммы с вашим «coroutine.launch», вместо этого используйте ключевое слово suspend для вашей функции, затем выполните их следующим образом:

suspend fun start() {}

suspend fun stop() {}

fun main() {
    scope.launch {
        start()
        stop()
    }
}

Но если вы хотите синхронизировать два метода, вы можете прочитать официальное Kotlin руководство по общему изменяемому состоянию , в котором представлено несколько хороших решений. И сделать что-то вроде этого:

val mutex = Mutex()

fun main() {
    mutex.withLock {
        start()
        stop()
    }
}
0 голосов
/ 31 января 2020

Используйте Deferred Задание с логическим значением, затем используйте await() для ожидания завершения. Как то так:

fun doSomeWork() {
    GlobalScope.launch(Dispatchers.Main) {
        val isStartingComplete = start().await()
        // await() will wait for the completion of the start() function
        if (isStartingComplete) {
            stop()
        }
    }
}

fun start(): Deferred<Boolean> {
    return GlobalScope.async (Dispatchers.IO) {
        // Do your start work
        true
    }
}

fun stop() {
    // Do your stop work
}
...