Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 这种模式如何导致死锁?_Go_Deadlock - Fatal编程技术网

Go 这种模式如何导致死锁?

Go 这种模式如何导致死锁?,go,deadlock,Go,Deadlock,我有一个(LRU)缓存对象,遇到死锁。。。这怎么可能 type cache struct { mutex *sync.Mutex ... } func (this *cache) Init() { // guaranteed to be called once, in main() this.mutex = &sync.Mutex{} } func (this *cache) f1() { // Pattern for acce

我有一个(LRU)缓存对象,遇到死锁。。。这怎么可能

  type cache struct {
    mutex *sync.Mutex
    ...
  }

  func (this *cache) Init() {  // guaranteed to be called once, in main()
    this.mutex = &sync.Mutex{}
  }

  func (this *cache) f1() {
     // Pattern for accessing mute, at the top of any function of 'cache' where needed.
     this.mutex.Lock()
     defer this.mutex.Unlock()
     ...
  }


  func (this *cache) f2() {
     this.mutex.Lock()
     defer this.mutex.Unlock()
     ...
  }
在出现的每个函数
mutex
中,只能使用此模式访问它。 然而。。。我陷入了僵局。这怎么可能呢

  type cache struct {
    mutex *sync.Mutex
    ...
  }

  func (this *cache) Init() {  // guaranteed to be called once, in main()
    this.mutex = &sync.Mutex{}
  }

  func (this *cache) f1() {
     // Pattern for accessing mute, at the top of any function of 'cache' where needed.
     this.mutex.Lock()
     defer this.mutex.Unlock()
     ...
  }


  func (this *cache) f2() {
     this.mutex.Lock()
     defer this.mutex.Unlock()
     ...
  }
注意:这段代码已经在生产服务器上运行了10个月,这是我第一次看到它


编辑:因此f1()可以(间接)调用f2(),以根据答案获得死锁。是的,但在我的代码中,这并没有发生,所以我真的想知道,如果
缓存的一个方法调用另一个方法,并且都包含
锁()
调用,死锁可能很容易发生

请参见此示例:

func (this *cache) f1() {
    this.mutex.Lock()
    defer this.mutex.Unlock()
    this.f2()
}

func (this *cache) f2() {
    this.mutex.Lock()
    defer this.mutex.Unlock()
}

func main() {
    c := &cache{}
    c.Init()
    c.f1()
    fmt.Println("Hello, playground")
}
输出(在上尝试):

注意,从一个方法到另一个方法不需要直接调用,它也可以是传递调用。例如,
cache.f1()

改进:

不要将你的接收者命名为this,它不是惯用的。你可以简单地称它为
c
。请在此处阅读更多信息:

您可以嵌入互斥体,这样使用起来很方便,无需进行初始化。请在此处阅读更多信息:


当然,这也会导致死锁。试穿一下。还请注意,这本身就暴露了互斥锁(因为嵌入类型以Lowcae字母开头),因此任何人都可以调用
Lock()
Unlock()
方法。取决于具体情况,这是否是问题。

如果
缓存的一个方法调用另一个方法,并且两个方法都包含
锁()
调用,则很容易发生死锁

请参见此示例:

func (this *cache) f1() {
    this.mutex.Lock()
    defer this.mutex.Unlock()
    this.f2()
}

func (this *cache) f2() {
    this.mutex.Lock()
    defer this.mutex.Unlock()
}

func main() {
    c := &cache{}
    c.Init()
    c.f1()
    fmt.Println("Hello, playground")
}
输出(在上尝试):

注意,从一个方法到另一个方法不需要直接调用,它也可以是传递调用。例如,
cache.f1()

改进:

不要将你的接收者命名为this,它不是惯用的。你可以简单地称它为
c
。请在此处阅读更多信息:

您可以嵌入互斥体,这样使用起来很方便,无需进行初始化。请在此处阅读更多信息:



当然,这也会导致死锁。试穿一下。还请注意,这本身就暴露了互斥锁(因为嵌入类型以Lowcae字母开头),因此任何人都可以调用
Lock()
Unlock()
方法。视情况而定,这是否是问题。

f1是否保证退出?它是否调用锁定互斥锁的其他函数?如果
缓存的一个方法调用另一个方法,并且两个方法都包含
lock()
调用,则很容易发生死锁。如上所述,这取决于
f1()
的作用。此外,您不需要创建新的互斥体并使用
Init()
。只需在结构中使用
sync.Mutex
而不是
*sync,Mutex
,因为设计的零值是有效的解锁Mutex。您是否在竞赛检测器下运行了此操作?我不确定它是否能检测到可能的多个锁尝试,但它可能会揭示一些东西…@Thomas这些方法并不要求直接相互调用。它可能是
cache.f1()
调用
foo()
,这是一个“独立”函数,如果
foo()
调用
cache.f2()
,我们将处于相同的死锁状态。见编辑后的答案。如果您的代码中甚至不存在此类可传递调用,那么您需要发布一个,否则它将成为离题。f1保证退出吗?它是否调用锁定互斥锁的其他函数?如果
缓存的一个方法调用另一个方法,并且两个方法都包含
lock()
调用,则很容易发生死锁。如上所述,这取决于
f1()
的作用。此外,您不需要创建新的互斥体并使用
Init()
。只需在结构中使用
sync.Mutex
而不是
*sync,Mutex
,因为设计的零值是有效的解锁Mutex。您是否在竞赛检测器下运行了此操作?我不确定它是否能检测到可能的多个锁尝试,但它可能会揭示一些东西…@Thomas这些方法并不要求直接相互调用。它可能是
cache.f1()
调用
foo()
,这是一个“独立”函数,如果
foo()
调用
cache.f2()
,我们将处于相同的死锁状态。见编辑后的答案。如果您的代码中甚至不存在此类可传递调用,那么您需要发布一个,否则它将成为非主题。它仅在包级别公开互斥,因为它没有导出。对的只是澄清一下OP,否则可能会让人困惑。@reticentroot不,那不是真的。在包内部,所有包级别标识符都是可见的。除此之外,仅导出标识符。类型
cache
本身不会导出,但例如,如果导出的函数返回类型
cache
*cache
的值,则任何人都可以调用其
Lock()
方法。啊,是的,您的右侧嵌入了互斥体,您可以通过使用类型为mutex的未报告成员来规避该问题。当然,初始化将不得不再次处理。。。所以我想这就是lol中优秀文档的来源。它是否可以抽象为“隐藏”锁?@reticentroot在某些情况下,它可以是,例如,您使用非指针字段,但请确保使用指向包装结构的指针,以避免意外复制互斥对象,并确保该字段可寻址,因为调用具有指针接收器的
Lock()
Unlock()
方法需要该地址。这在没有初始化的情况下是可能的,因为
sync.Mutex
的零值是一个有效的、未锁定的互斥体。它只在包级别公开互斥体,因为它是