当我们使用非可重入锁时。

huangapple go评论61阅读模式
英文:

when we will use not re-entrance lock

问题

作为 Golang 的初学者,我发现《Go 程序设计语言》一书中提到的 Golang 的互斥锁(mutex)不支持重入。他们解释了原因:

> Golang 的互斥锁不支持重入是有充分理由的。互斥锁的目的是确保在程序执行的关键点上,共享变量的某些不变量得到维护。其中一个不变量是“没有 goroutine 正在访问共享变量”,但是互斥锁可能还要保护其他特定于数据结构的不变量。当一个 goroutine 获取了互斥锁之后,它可以假设这些不变量成立。在持有锁的期间,它可以更新共享变量,从而暂时违反这些不变量。然而,当它释放锁时,它必须保证恢复了顺序,并且这些不变量再次成立。尽管重入锁可以确保没有其他 goroutine 访问共享变量,但它无法保护这些变量的其他不变量。

看起来这个解释已经足够详细了,但不幸的是我还是不太理解。我仍然不知道在什么情况下我们应该使用不支持重入的互斥锁,如果不使用会有什么坏的结果。如果有人能给我一个例子,我将不胜感激。

英文:

As a beginner of golang, I find the mutex of golang is not re-entranceLock from the book The Go Programming Language. And they explain the reason as:

>There is a good reason Go’s mutexes are not re-entrant. The purpose of a mutex is to ensure that certain invariants of the shared variables are maintained at critical points during program execution. One of the invariants is "no goroutine is accessing the shared variables," but there may be additional invariants specific to the data structures that the mutex guards. When a goroutine acquires a mutex lock, it may assume that the invariants hold. While it holds the
lock, it may update the shared variables so that the invariants are temporarily violated.
However, when it releases the lock, it must guarantee that order has been restored and the invariants hold once again. Although a re-entrant mutex would ensure that no other goroutines are accessing the shared variables, it cannot protect the additional invariants of those variables.

it seemed the explain is detail enough, unfortunately I can't get it. I still don't know when we should use not re-entranceLock, and if not what bad surprise will I receive? I will appreciate if anyone can give me an example.

答案1

得分: 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 {
			// 安全计数器不希望在这里发生!
			// 程序将在SetEnabled中发生panic
			counter.SetEnabled(false)
		}
		return value + 1
	}
	for i := 0; i < 100; i++ {
		doAction()
		counter.Increment()
	}
	fmt.Println(counter.Count())
}

func doAction() {
	// 一些操作
}

IncrementSetEnabled都会获取锁,因为它们不能在执行过程中允许enabledcount的值发生变化。然而,如果锁是可重入的(递归的),那么它将被允许(因为两个调用都在同一个goroutine上运行)。

英文:

Here's an example of <b>bad</b> code just to illustrate the issue:

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
)

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() &gt; maxCount {
			// Safe counter doesn&#39;t expect this here!
            // The program will panic in SetEnabled
			counter.SetEnabled(false)
		}
		return value + 1
	}
	for i := 0; i &lt; 100; i++ {
		doAction()
		counter.Increment()
	}
	fmt.Println(counter.Count())
}

func doAction() {
	// some action
}

Both Increment and SetEnabled acquire locks because they can't allow the values of enabled and count to change while they're in the middle of something. However, if the lock was re-entrant (recursive), then it would be allowed (since both calls run on the same goroutine).

huangapple
  • 本文由 发表于 2017年6月17日 19:49:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/44604261.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定