当互斥锁锁定地图对象时打印地图对象。

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

Printing map object when it is locked by mutex

问题

我不确定为什么互斥锁(mutex)没有按照我预期的方式工作。任何建议都会对我有所帮助。

这是我的代码:

package main

import (
	"fmt"
	"sync"
	"time"
)

type Container struct {
	mu       sync.Mutex
	counters map[string]int
}

func (c *Container) inc(name string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.counters[name]++

	// fmt.Println("in", name, c.counters)
	// 这个打印语句在 goroutine 之间产生了问题
	time.Sleep(time.Second)
}

func main() {
	c := Container{
		counters: map[string]int{"a": 0, "b": 0},
	}

	var wg sync.WaitGroup

	doIncrement := func(name string, n int) {
		for i := 0; i < n; i++ {
			c.inc(name)
			fmt.Println(name, c.counters)
		}
		wg.Done()
	}

	wg.Add(3)
	go doIncrement("a", 2)
	go doIncrement("b", 2)
	go doIncrement("a", 2)

	wg.Wait()
	fmt.Println(c.counters)
}

当我运行这段代码时,我得到了奇怪的输出:

a map[a:2 b:0]
a map[a:2 b:0]
b map[a:2 b:1]
a map[a:4 b:1]
a map[a:4 b:1]
b map[a:4 b:2]
map[a:4 b:2]

我期望能够看到一些日志,其中可以看到 a 增加到 1、2、3、4。

当我移除 inc 函数中的注释时,我可以看到预期的日志:

in a map[a:1 b:0]
a map[a:1 b:0]
in a map[a:2 b:0]
a map[a:2 b:0]
in b map[a:2 b:1]
b map[a:2 b:1]
in a map[a:3 b:1]
a map[a:3 b:1]
in a map[a:4 b:1]
a map[a:4 b:1]
in b map[a:4 b:2]
b map[a:4 b:2]
map[a:4 b:2]

请问有什么问题导致互斥锁没有按照预期工作?

英文:

I am not sure why mutex is not working as I expected. Any advice will help me.

Here is my code.

package main

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

type Container struct {
    mu       sync.Mutex
    counters map[string]int
}

func (c *Container) inc(name string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.counters[name]++
    
    // fmt.Println(&quot;in&quot;, name, c.counters) 
    // This print is doing tricks between goroutines
    time.Sleep(time.Second)
}

func main() {
    c := Container{

        counters: map[string]int{&quot;a&quot;: 0, &quot;b&quot;: 0},
    }

    var wg sync.WaitGroup

    doIncrement := func(name string, n int) {
        for i := 0; i &lt; n; i++ {
            c.inc(name)
            fmt.Println(name, c.counters)
        }
        wg.Done()
    }

    wg.Add(3)
    go doIncrement(&quot;a&quot;, 2)
    go doIncrement(&quot;b&quot;, 2)
    go doIncrement(&quot;a&quot;, 2)

    wg.Wait()
    fmt.Println(c.counters)
}

When I ran this, I got strange outputs.

a map[a:2 b:0]
a map[a:2 b:0]
b map[a:2 b:1]
a map[a:4 b:1]
a map[a:4 b:1]
b map[a:4 b:2]
map[a:4 b:2]

I expected some logs where I can see a increased to 1,2,3,4

When I removed comments in inc function;
I could see the expected logs.

in a map[a:1 b:0]
a map[a:1 b:0]
in a map[a:2 b:0]
a map[a:2 b:0]
in b map[a:2 b:1]
b map[a:2 b:1]
in a map[a:3 b:1]
a map[a:3 b:1]
in a map[a:4 b:1]
a map[a:4 b:1]
in b map[a:4 b:2]
b map[a:4 b:2]
map[a:4 b:2]

答案1

得分: 3

在这个循环中:

for i := 0; i < n; i++ {
    c.inc(name)  // 这个在互斥锁被锁定时运行
    fmt.Println(name, c.counters)  // 这个在互斥锁未锁定时运行
}

Println 在互斥锁保护的区域之外运行。两个 goroutine 同时尝试增加 "a",一个增加后等待。当该增加函数返回时,第二个函数进入并增加,然后第一个函数的 Println 运行,然后第二个函数的 Println 打印相同的内容。

所以,互斥锁按预期工作,但你在互斥锁保护的区域之外进行了打印。

英文:

In this loop:

for i := 0; i &lt; n; i++ {
            c.inc(name)  ---&gt; This runs with mutex locked
            fmt.Println(name, c.counters)  --&gt; This runs with mutex unlocked
}

The Println runs outside the mutex lock. Two goroutines attempt to increment "a" at the same time, one increments and then waits. When that increment function returns, the second one goes in and increments, then Println from the first one runs, then Println from the second one prints the same thing.

So, mutex is working as expected, but you are printing outside the region protected by mutex.

huangapple
  • 本文由 发表于 2022年12月1日 11:50:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/74636766.html
匿名

发表评论

匿名网友

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

确定