最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kotlin - Why does a race conditon occur upon launching multiple coroutines - Stack Overflow

programmeradmin1浏览0评论

Using Dispatchers.Default and I know that the coroutines are distributed across multiple threads. But what exactly is going on that causes the value here to be incorrect?

fun main() = runBlocking{
    var x =0
    repeat(10_000){
        launch(Dispatchers.Default){
            ++x
        }
    }
    delay(1.seconds)
    println(x)
}

Aren't the coroutines made sequentially and done with once they individually finish incrementing the value once? Why get varying results? What does sequential even mean in coroutine creation and execution?

Using Dispatchers.Default and I know that the coroutines are distributed across multiple threads. But what exactly is going on that causes the value here to be incorrect?

fun main() = runBlocking{
    var x =0
    repeat(10_000){
        launch(Dispatchers.Default){
            ++x
        }
    }
    delay(1.seconds)
    println(x)
}

Aren't the coroutines made sequentially and done with once they individually finish incrementing the value once? Why get varying results? What does sequential even mean in coroutine creation and execution?

Share Improve this question edited Mar 12 at 8:44 Ken Kiarie asked Mar 12 at 6:46 Ken KiarieKen Kiarie 1411 gold badge1 silver badge8 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

The basic issue1 is that ++x is not an atomic operation and it therefore isn't thread-safe.

++x basically executes like this:

x = x + 1

And this statement has two parts, x + 1 and x = <result>. These parts are not guaranteed to be executed without another thread interfering. So two threads may, at the same time, retrieve the same x and calculate the same result x + 1, and only then they start writing the result back to the variable. But the deed is already done: Since the first thread was too slow to increment the variable and write it back in time, the second thread repeated the same increment, effectively losing one increment, resulting in x being 1 smaller than it should be.

This effect accumulates over time. Depending on the hardware involved (especially the number of threads the Default dispatcher has which is, by default, equal to the number of processor cores) this happens more or less frequently.

This is a common issue when accessing a shared mutable state in a multi-threaded environment. You need some kind of synchronization to fix that. See the link for more.


Regarding your last paragraph: Although a couroutine (and suspend functions, and all non-suspending code) is executed sequentially from top to bottom, other coroutines may be executed in parallel to this coroutine.


1 Another potential issue is the delay(1). I guess you do that to wait for the coroutines to finish. But that may take longer than 1ms (largely depending on the hardware), but when you print x before all coroutines finished you also won't get the correct result. You can wrap the loop in coroutineScope { ... } instead.

发布评论

评论列表(0)

  1. 暂无评论