Search code examples
kotlin-coroutineswithcontext

is this right to use coroutines in a non coroutine context


Having a Processor class, trying to replace some of the code with coroutines. Since it is in a non coroutines context so val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob) is added and used for start coroutines.

Added CoroutineScope, and using serviceScope.launch{} in the place which was using Thread{}.start().

Inside the function restart(), it replaced the using of CountDownLatch with

serviceScope.launch {
                withContext(Dispatchers.IO) {

                    doReset()
                }
            }

Question: this launch/withContext actually does not stop the code execution of the next if (!conDoProcess) -- so it fails to do what the latch used to do.

what is the right way to stop the code execution until the doReset() . is done?

Another question, when dispose this Processor object it calls serviceScope.cancel(),

what is the difference if call with serviceJob.cancel()?

class Processor {

    private val serviceJob = Job()
    private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)

            .........

    /* return false if the it does not start the processing */
    fun restart(): Boolean {

        synchronized(_lock) {

            .........

            // 1.old code using latch to wait

            /******************
            val latch = CountDownLatch(1)
            streamThreadPoolExecutor.execute {

                doReset()  //

                latch.countDown()
            }
            latch.await(3, TimeUnit.SECONDS) // wait at most for 3 seconds if no one calls countDown

            *******************/

            // 2. change to using coroutines to suspend

            serviceScope.launch {
                withContext(Dispatchers.IO) {

                    doReset()
                }
            }

            // wait until reset is done
            if (!conDoProcess) {// the doRest() should update conDoProcess
                return false
            }

            for (i in providers.indices) {
                val pr = provider[i]
                serviceScope.launch {
                    pr.doProcess()
                }
            }

            return true
        }
    }

    fun dispose() {
        synchronized(_lock) {

            .........
            serviceScope.cancel()

            // or should it use
            // serviceJob.cancel()
            //==========>
        }
    }
}

Solution

  • I think it used the serviceScope.launch wrong, it should include the rest part after the blocking part withContext(Dispatchers.IO), but inside the serviceScope.launch.

            // 2. change to using coroutines to suspend
    
            serviceScope.launch {
                withContext(Dispatchers.IO) {
    
                    doReset()
                }
    
                // wait until reset is done
                if (!conDoProcess) {// the doRest() should update conDoProcess
                  return false
                }
    
                for (i in providers.indices) {
                  val pr = provider[i]
                  serviceScope.launch {
                      pr.doProcess()
                  }
                }   
            }
    
            return true