0

I am trying to understand how does coroutines access other thread's data. Just have a look on below kotlin program in which I tried to understand the variableAccessCount in main thread can be accessed from Coroutine C1 & Coroutine C2 however as per my understanding coroutines are piece of code which runs on different threads and in Android threads can't be touched directly there is mechanism to do that such as Handler, in coroutine also we do have withContext() but specific to this example,

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.coroutines.coroutineContext

var variableAccessCount = 0

fun main() {
    println("${Thread.currentThread()}")

    GlobalScope.launch {//Coroutine C1
        println("${Thread.currentThread()}")
        firstAccess() }

    GlobalScope.launch {//Coroutine C2
        println("${Thread.currentThread()}")
        secondAcess() }

    Thread.sleep(2000L)

    print("The variable is accessed $variableAccessCount number of times")
}

suspend fun firstAccess() {
    delay(500L)
    variableAccessCount++
}

suspend fun secondAcess() {
    delay(1000L)
    variableAccessCount++
}

Would somebody help me to understand How does synchronization happens under the hood for variable var functionCalls = 0 This variable is declared in Main thread and can be accessed from both suspend functions (completeMessage & improveMessage), which are running inside coroutine but on different worker thread.

Program O/P

Thread[main,5,main]
Thread[DefaultDispatcher-worker-3,5,main]
Thread[DefaultDispatcher-worker-2,5,main]
The variable is accessed 2 number of times
Rahul Matte
  • 1,151
  • 2
  • 23
  • 54
  • It doesn't. You should be using `AtomicInteger` or `LongAdder`. – Nicolas Aug 22 '20 at 01:02
  • It is executing please try from above code – Rahul Matte Aug 22 '20 at 01:11
  • Yes it works. But it's not guaranteed to, you're exposing yourself to a race condition. See this answer for [Why is i++ not atomic?](https://stackoverflow.com/a/25168105/5288316). What you call "synchronization" is normally called "atomicity" and is handled by classes like the ones I mention above. Also threads may have separate execution, but they still share memory. – Nicolas Aug 22 '20 at 01:22
  • Understood but then with respect to your above comment, in Android, UI can’t touch UI thread from another thread – Rahul Matte Aug 22 '20 at 01:27
  • 2
    It can't but that's a limitation of the Android framework, not the JVM (or Kotlin). – Nicolas Aug 22 '20 at 01:42
  • Amazing dot is now connected, so can we say the answer to above question is to use atomicity and withContext to switch the thread! – Rahul Matte Aug 22 '20 at 01:50

1 Answers1

1
  • Use AtomicInteger:
val variableAccessCount = AtomicInteger(0)

suspend fun firstAccess() {
    delay(500L)
    variableAccessCount.incrementAndGet()
}

suspend fun secondAcess() {
    delay(1000L)
    variableAccessCount.incrementAndGet()
}
  • Thread confinement fine-grained
val counterContext = newSingleThreadContext("CounterContext")
var variableAccessCount = 0

suspend fun firstAccess() {
    delay(500L)
    withContext(counterContext) { variableAccessCount++ }
}

suspend fun secondAcess() {
    delay(1000L)
    withContext(counterContext) { variableAccessCount++ }
}
  • Mutual exclusion
val mutex = Mutex()
var variableAccessCount = 0

suspend fun firstAccess() {
    delay(500L)
    mutex.withLock  { variableAccessCount++ }
}

suspend fun secondAcess() {
    delay(1000L)
    mutex.withLock  { variableAccessCount++ }
}