并发读写

Concurrent read write

下面是我的代码,其中两个变量在回调时更新,回调每 50 毫秒调用一次。还有一个 reader 线程,每 50 毫秒唤醒一次并读取变量。

在经历了this之后,我猜想在某些情况下,读取的线程会在收到回调时唤醒,因为我在读取和写入时没有锁定同一个互斥锁,在这种情况下,将导致读取的内存不一致。

然而,当我运行它时,这种情况就不会发生了。是我运行时间不够还是我理解有误?

recursive_mutex mutex1
recursive_mutex mutex2
var1, var2

//called every 50ms
onUpdateListener() {
    lock(mutex1)
    update var1
    update var2
}

VarReaderThread::readVar() {
    sleep(50)
    while(true) {
        {
        lock(mutex2)
        read var1
        read var2
        sleep(50)
        }
   }
}

当两个或多个线程正在访问共享数据时发生数据竞争,其中至少一个线程是写操作,其中一个或多个线程可能遇到不一致的状态。

提供的代码有两个互斥体,一个用于读取,一个用于写入。 这绝不会排除一个线程读取共享数据(示例中的 var1var2),而另一个线程正在写入共享数据,或者更准确地说,在一个线程开始写入其中一个之后和完成之前在中间状态被认为是代码逻辑及其目的参数中的不一致状态的情况下写入另一个。

需要一个mutex才能使读写互斥。 顺便说一句,不清楚为什么要声明递归互斥体。仅当给定线程可能遇到要求它获得它已持有的互斥锁的代码时才需要这样做。在可能的情况下设计和编码这种情况是更好的设计。

已引入显式 unlock 步骤,根据编码模型,这些步骤可能需要也可能不需要(在 C 中需要,在 C++ 中使用 std::lock_guardsynchronizedfinally 在 Java 等)。

引入了一些条件来指示正确的终止条件。 while(true) 是一种不好的做法,除非某些其他条件会正常终止它。

更复杂的模型可能会使用 'shared mutex',其中多个线程可能会以 'read' 模式保存它,但如果一个线程以 'write' 模式保存它,则只有一个。这可能需要也可能不需要一些信号来确保 'write' 不会陷入许多读者无休止地阻止 'write' 访问的活锁状态。

mutex mutex_v1_v2 //The mutex controlling shared state var1, var2.
var1, var2

//called every 50ms
onUpdateListener() {
    lock(mutex_v1_v2)
    update var1
    update var2
    unlock(mutex_v1_v2)
}

VarReaderThread::readVar() {
    sleep(50)
    while(!finished) {
        lock(mutex_v1_v2)
        read var1
        read var2
        unlock(mutex_v1_v2)
        sleep(50) //V. V. important to sleep not holding the mutex!
   }
}