返回
协程 Mutex 无法阻止并行修改?这篇文章告诉你原因!
Android
2024-03-17 16:02:00
协程 Mutex 难以阻止多个协程修改或读取数据
问题
当在协程之间共享重要数据时,使用 Mutex 来防止并发的修改或读取操作至关重要。然而,在某些情况下,即使使用 Mutex,也可能出现并行修改异常。
考虑以下示例:我们有一个火车列表(trains),我们需要在协程之间共享。为了保护该列表,我们在修改方法中使用了 Mutex。然而,在removeUnusedTrains
方法中,我们没有使用 Mutex,导致并行修改异常。
原因
并行修改异常发生的原因是:
removeUnusedTrains
方法在不加锁的情况下修改trains
列表。- 同时,另一个协程也可能正在访问该列表。
- 当
removeUnusedTrains
方法尝试修改列表时,它可能会与另一个协程并行操作,从而导致异常。
解决方法
解决此问题的关键是始终在修改trains
列表时获取mutex
锁。这将确保一次只有一个协程可以修改列表,从而避免并发修改异常。
修改后的代码如下:
class TrainService {
private var trains : MutableList<Train> = emptyList<Train>().toMutableList()
private val mutex = Mutex()
suspend fun addTrain(newTrain: MatOfPoint, trainColor: Scalar) = mutex.withLock {
for(train in trains) {
when {
train.isSame(newTrain) -> return true
}
}
val train = Train(newTrain, trainColor)
trains.add(train)
}
suspend fun removeUnusedTrains() = mutex.withLock {
val iterator = trains.iterator()
while (iterator.hasNext()) {
val train = iterator.next()
if (!train.changed) {
iterator.remove()
} else {
train.changed = false
}
}
Log.d("TrainService", "Trains now: ${trains.joinToString()}")
}
}
常见问题解答
1. Mutex 是处理协程并发修改的唯一方法吗?
不,还有其他方法可以处理协程并发修改,例如使用原子变量或不可变数据结构。
2. 即使使用 Mutex,为什么仍然可能出现并发修改异常?
如果在获取 Mutex 锁之前对数据进行了修改,则可能会出现并发修改异常。
3. 如何避免并行修改异常?
始终在修改共享数据时获取 Mutex 锁。
4. Mutex 会影响协程性能吗?
是的,Mutex 会引入一些开销,但它对于防止并发修改异常至关重要。
5. 何时使用 Mutex?
当多个协程需要访问和修改共享数据时,应使用 Mutex。