【问题标题】:Acquiring a lock over a memory address instead of variable in golang在golang中获取内存地址而不是变量的锁
【发布时间】:2019-09-11 02:56:20
【问题描述】:

我有一个名为 Setter 的接口。名为 SetterImpl 的结构体实现了这个接口,有 2 个 setter,都设置了 2 个接口。

type Setter interface {
    A() *AInterface
    B() *BInterface
}
type SetterImpl struct {
    a *AInterface
    b *BInterface
}

func (s *SetterImpl) A(a *AInterface) {
    a = a
}

func (s *SetterImpl) B(b *AInterface) {
    b = b
}

func returnSetter(a *AInterface, b *BInterface) Setter {
    return &SetterImpl{a:a, b:b}
}

上述方法返回的setter在堆中(比如SHeap)并发送到gRPC服务器。现在,我想更新 SetterImpl 中的 a 和 b,以便 gRPC 服务器使用新值。

所以我现在有 2 个 goroutine;一个是 gRPC 服务器主 goroutine(比如 MAIN),另一个是分叉的(比如 FORKED),它只是更新设置器字段。

如果我在 FORKED 中使用 Mutex,那本质上就是添加一个栅栏(如 java)。它实际上并没有锁定任何变量(除了它自己)。 我不希望 MAIN 在 FORKED 更新它们时能够读取存储在 SHeap 中的 a 和 b。服务器中的 API 线程(goroutines)在读取 SHeap 中的值之前不会获取 Read Mutex。那么,甚至有可能做我想要实现的目标吗?如果是,我该如何实现?

【问题讨论】:

  • 我不确定这里的“SHeap”指的是什么,但是锁定内存地址不是您应该尝试的。互斥锁只有在所有参与者都使用锁的情况下才有效; main 必须在读取共享内存之前获得一个锁。
  • 看起来你有很强的 Java 背景,你可能在你的 Go 编程中携带了太多的经验。 Go 与 Java 非常不同。虽然语法表面上相似,但好的 Go 代码可以工作并且编写方式非常不同。标准的 Java 接口/实现模式是 very un-Go。 Goroutines 和线程不等价,也不等价于 fork 一个进程。在可能的情况下,通道优先于锁定,如果不是,互斥锁是 锁定机制。

标签: go locking mutex heap-memory goroutine


【解决方案1】:

我认为你不能在 Go 中锁定变量。您只能锁定一个代码段。

m.Lock()
// do stuff
m.Unlock()

使用“interface”与“Impl”模式,您无中生有地为自己制造了一个问题。

您可以通过使用常规函数来简化您的生活。然后你可以把锁放在一个函数里面,保证它会受到保护。

由于你是在做一个接口,所以你不能保证实现这个接口的函数的内容。

【讨论】:

    【解决方案2】:

    变量不能被锁定。所以我想做的事情是不可能的。 我所做的解决方法是将RWMutex 添加到 SetterImpl 并执行

    mux.RLock()
    defer mux.RUnlock()
    

    在 SetterImpl 中的 a 和 b 的 getter 中。当我想在 FORKED 中设置 a 和 b 时,我使用了

    mux.Lock()
    defer mux.Unlock()
    

    这样,如果通过 FORKED 获得了写锁,那么此时就无法获得读锁。这是可能的,因为在 SHeap 中创建的 RWLock 字段用作全局变量(即,此互斥锁永远不会更改并沿 FORKED 传递)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-26
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 2017-05-10
      • 1970-01-01
      • 2017-12-11
      相关资源
      最近更新 更多