当我们不使用重新进入锁定时

时间:2017-06-17 11:49:54

标签: go locking

作为golang的初学者,我发现golang的互斥 不是re-entranceLock 来自书籍The Go Programming Language。他们解释原因:

  

Go的互斥体不可重入是有充分理由的。互斥锁的目的是确保在程序执行期间在关键点维护共享变量的某些不变量。其中一个不变量是"没有goroutine访问共享变量,"但是可能存在特定于互斥锁保护的数据结构的其他不变量。当goroutine获取互斥锁时,它可能会认为不变量成立。虽然它持有   锁定,它可能会更新共享变量,以便暂时违反不变量。   但是,当它释放锁时,它必须保证订单已经恢复并且不变量再次保持。虽然可重入的互斥锁可以确保没有其他goroutine访问共享变量,但它无法保护这些变量的其他不变量。

似乎解释很详细,不幸的是我无法得到它。我还不知道什么时候应该使用不能重新入口,如果没有,我会收到什么不好的惊喜?如果有人能给我一个例子,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

以下是糟糕代码的示例,仅用于说明问题:

package main

import (
    "fmt"
    "sync"
)

type SafeCounter struct {
    lock      sync.Mutex
    count     int
    enabled   bool
    NextValue func(int) int
}

const maxCount = 10

func (c *SafeCounter) Count() int {
    return c.count
}

func (c *SafeCounter) Increment() {
    c.lock.Lock()
    if c.enabled {
        c.count = c.NextValue(c.count)
    }
    c.lock.Unlock()
}

func (c *SafeCounter) SetEnabled(enabled bool) {
    c.lock.Lock()
    c.enabled = enabled
    if !enabled {
        c.count = 0
    }
    c.lock.Unlock()
}

func main() {
    var counter SafeCounter
    counter.SetEnabled(true)
    counter.NextValue = func(value int) int {
        if counter.Count() > maxCount {
            // Safe counter doesn't expect this here!
            // The program will panic in SetEnabled
            counter.SetEnabled(false)
        }
        return value + 1
    }
    for i := 0; i < 100; i++ {
        doAction()
        counter.Increment()
    }
    fmt.Println(counter.Count())
}

func doAction() {
    // some action
}

IncrementSetEnabled都获得锁定,因为他们不能允许enabledcount的值在他们位于中间时发生变化东西。但是,如果锁是重入(递归),那么它将被允许(因为两个调用都在相同的goroutine上运行)。