我想要一个golang RWMutex API语义的模型(https://pkg.go.dev/sync#RWMutex);特别是我想要读者和作者的阻塞行为.

下面是我的读写互斥锁模型:

typedef RWLock {
  chan writeComplete = [0] of {bit};
  chan allowWrite = [0] of {bit};
  int readers;
  bit writing;
  int writeWaiters;
  int readWaiters
}


/* RWLock actions */

inline acquire_read(lock) {
  do
    :: atomic {
      if
        :: lock.writing == 1 ->
       lock.readWaiters++;
       lock.writeComplete?0;
       lock.readWaiters--;
       break
        :: else ->
       lock.readers++;
       break
      fi
    }
  od
}

inline release_read(lock) {
    atomic {
      lock.readers--;
      lock.readers == 0 ->
end:   lock.writeComplete!0
    }
}

inline acquire_write(lock) {
  do
    :: atomic {
      if
    :: lock.writing == 0 -> 
       lock.writing = 1;
       break;
    :: else ->
       lock.writeWaiters++;
       lock.allowWrite?0;
       lock.writeWaiters--
      fi
    }
  od
}

inline release_write(lock) {
  atomic {
    assert(lock.writing == 1);
    lock.writing = 0
    if
    :: lock.writeWaiters > 0 ->
        lock.allowWrite!0
    :: else ->
        skip
    fi
    if
    :: lock.readWaiters > 0 ->
        lock.writeComplete!0;
    :: else ->
        skip
    fi
  }
}

我不能完全肯定这是不是正确的.理想情况下,我的问题的答案应该是以下几类之一:

  1. 向我保证我的模型是正确的
  2. 告诉我这是错的,告诉我如何修复它
  3. 你不知道它是否正确,但你可以提供一些指导,告诉我如何使用Promela模型有效地测试它

到目前为止,我有一个简单的模型,它是这样使用的:

( complete example here --

int counter = 0;


proctype Writer(RWLock lock) {
  acquire_write(lock);
  counter = counter + 1;
  printf("Writer incremented counter to %d\n", counter);
end: release_write(lock);
}

proctype Reader(RWLock lock) {
  int localCounter;
  acquire_read(lock);
  localCounter = counter;
  printf("Reader read counter: %d\n", localCounter);
end: release_read(lock);
}

init {
  RWLock myLock;
  myLock.readers = 0;
  myLock.writing = 0;
  myLock.writeWaiters = 0;
  myLock.readWaiters = 0

  run Writer(myLock);
  run Reader(myLock)
end: skip
}

推荐答案

Disclaimer:虽然我的博士学位是正规的,但我已经15年没有做过任何模型了,我从来没有使用过Promela.

这是我的笔记.

  1. acquire_write应等待,直到所有读取器释放锁.你查了lock.writing == 0,但lock.readers > 0呢?

try 以下方案:

Reader does acquire_read and proceeds
Writer does acquire_write and ?

据我们所知,Writer继续,而规范要求它阻止.

  1. 我认为,acquire_read没有满足以下要求:

如果任何Goroutine在锁已被一个或多个读取器持有时调用Lock,则对RLock的并发调用将被阻止,直到写入器获得(并释放)锁,以确保锁最终对写入器可用.

模型acquire_read不仅应该在lock.writing == 1时等待,而且应该在lock.writeWaiters > 0时等待.

try 以下方案:

ReaderA does acquire_read and proceeds
Writer does acquire_write and blocks
ReaderB does acquire_read and ?

根据规范,它应该会被阻止.按照你们的型号,是lock.readers++美元,对吗?

  1. 哦,天哪.点菜.

该规范要求:

对于任何对RLock的调用,都存在一个n,使得第n次对RLock的调用"在RLock调用之前",并且对应的对RLock的调用"在Lock调用之前".

我找不到模型是如何将其形式化的.

try 以下方案:

ReaderA does acquire_read and proceeds
WriterA does acquire_write and blocks
ReaderB does acquire_read and blocks /* since WriterA.acquire_write is pending */
WriterB does acquire_write and blocks * since WriterB.release_write hasn't been esecuted called yet */
ReaderC does acquire_read and /* blocks since there are pending writers */
ReaderA does release_read
/* Expected (not sure): 
   WriterA unblocks, what about your model?
   WriterB is blocked, 
   ReaderB and ReaderC are blocked due to the ordering requirement: 
     WriterA.acquire_read was before ReaderB.acquire_read 
*/
WriterA does release_write
/* Expected (not sure): 
   ReaderB proceeds, 
   WriterB is blocked due to the ordering requirement: 
     ReaderB.acquire_read was called before WriterB.acquire_read 
   ReaderC is blocked due to pending writer
*/ 
ReaderB does release_read
/* Expected (not sure): 
   WriterB proceedes due to the ordering requirement: 
     it was blocked before ReaderC
   ReaderC 
*/

Go相关问答推荐

链自定义GRPC客户端拦截器/DialOptions

如何在VSCode中为特定的.go文件创建调试配置?

如何确定泛型类型在运行时是否可比较?

Kafka golang 生产者在错误后更改分区计数

Kperf 构建失败

我应该先解锁然后再广播吗?

使用 httptest 对 http 请求进行单元测试重试

对 CSV 进行单元测试失败

闭包所处的环境范围是什么?

Golang Oauth2 服务帐户返回空刷新令牌字符串

转换朴素递归硬币问题时的记忆错误

如何在切片增长时自动将切片的新元素添加到函数参数

为什么此代码在运行命令 error="exec: not started" 时出现错误?

为什么 x/net/html Token().Attr 上的 len 在此处为空切片返回非零值?

如何在循环中旋转图像以便在 golang 中创建 GIF?

Grafana/Prometheus 将多个 ip 可视化为查询

golang 如何从字符串中查找表情符号?

从另一个没有重复的确定性 int

Golang API 的 HTTPS

有没有办法在golang中映射一组对象?