Lock when reading a ConflatedChannel's value. (#3248)
Reads in `isBufferEmpty()` were detected as a race by internal tests.
The relevant stack snippets are:
```
Read of size 4 at 0x0000cf809644 by thread T10 (mutexes: write M0, write M1):
#0 kotlinx.coroutines.channels.ConflatedChannel.isBufferEmpty()Z ConflatedChannel.kt:22
```
and:
```
Previous write of size 4 at 0x0000cf809644 by thread T32 (mutexes: write M2, write M3, write M4, write M5, write M6, write M7):
#0 kotlinx.coroutines.channels.ConflatedChannel.updateValueLocked(Ljava/lang/Object;)Lkotlinx/coroutines/internal/UndeliveredElementException; ConflatedChannel.kt:131
```
diff --git a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
index f7f60cf..177e80c 100644
--- a/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/ConflatedChannel.kt
@@ -19,7 +19,7 @@
*/
internal open class ConflatedChannel<E>(onUndeliveredElement: OnUndeliveredElement<E>?) : AbstractChannel<E>(onUndeliveredElement) {
protected final override val isBufferAlwaysEmpty: Boolean get() = false
- protected final override val isBufferEmpty: Boolean get() = value === EMPTY
+ protected final override val isBufferEmpty: Boolean get() = lock.withLock { value === EMPTY }
protected final override val isBufferAlwaysFull: Boolean get() = false
protected final override val isBufferFull: Boolean get() = false
@@ -139,5 +139,5 @@
// ------ debug ------
override val bufferDebugString: String
- get() = "(value=$value)"
+ get() = lock.withLock { "(value=$value)" }
}