是否有可能与 golang chan 存在竞争条件?

我的目标是创建一个简单的 websocket 服务器。我使用 chan 来分发消息,例如通过调用<-messageChan. 有messageChan许多作家和读者。

但是,这个StackOverflow 问题让我害怕导致无意中的死锁。

我做了什么:

  1. 创建一个基本上做的测试:

    1. chan int用 0 到 1000填充 a 。

    2. 创建 100 个 goroutine 来调用<-chan并将其添加到map[int]bool.

    3. t.Fatal如果不是 1000,则调用。len(map[int]bool)换句话说,竞争条件。

然而,测试并没有失败。恐怕,我做错了什么,chan可能会陷入僵局。

代码

main_test.go

package main


import (

    "log"

    "sync"

    "testing"

)


type MapMux struct {

    sync.RWMutex

    m map[int]bool

    sync.WaitGroup

}


func (mux *MapMux) AddInt(i int) {

    mux.RLock()

    if _, isExist := mux.m[i]; isExist {

        log.Fatal("race condition")

    }

    mux.RUnlock()

    mux.Lock()

    mux.m[i] = true

    mux.Unlock()

    mux.Done()

}


func TestChanRaceCondition(t *testing.T) {

    l := 1000

    c := make(chan int, l)

    defer close(c)

    for i := 0; i < l; i++ {

        c <- i

    }


    mux := MapMux{sync.RWMutex{}, map[int]bool{}, sync.WaitGroup{}}


    mux.Add(l)


    for i := 0; i < 100; i++ {

        go func(key int) {

            for {

                payload := <-c

                log.Printf("go%d: %d", key, payload)

                mux.AddInt(payload)

            }

        }(i)

    }


    mux.Wait()


    if len(mux.m) != l {

        t.Fatal("expected len:", l, ", actual len:", len(mux.m))

    }

}

编辑:

  1. 该代码在该map[int]bool字段中查找重复项。编辑:这是因为defer close(c)。我应该检查通道是否为每个操作打开。

无论如何,这就是我学到的。希望这对新的 Golangers 有所帮助。

学习到教训了:

  1. 一个频道有很多作者和很多读者是可以的。

  2. 总是检查val, isOpen := <-chan。如果isOpen== false,则停止使用该频道。

  3. sync.RWMutex.RLock()不保证其他 goroutine 对地图进行更改。所以,当心。这是应该做的。

 func (mux *MapMux) AddInt(i int) {

     mux.RLock()

     if _, isExist := mux.m[i]; isExist {

         log.Fatal("race condition")

     }

     mux.RUnlock()

     mux.Lock()

     if _, isExist := mux.m[i]; isExist {

         log.Fatal("race condition")

     }

     mux.m[i] = true

     mux.Unlock()

     mux.Done()

 }


12345678_0001
浏览 78回答 1
1回答

MMMHUHU

如果您在 goroutine 之间共享内存,就会发生数据竞争。如果你不在 goroutine 之间共享内存,你担心的那种数据竞争就不会发生。可能还有其他竞争条件,例如您的AddInt方法中的竞争条件。正确的版本应该是:func (mux *MapMux) AddInt(i int) {&nbsp; &nbsp; mux.RLock()&nbsp; &nbsp; if _, isExist := mux.m[i]; isExist {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal("race condition")&nbsp; &nbsp; }&nbsp; &nbsp; mux.RUnlock()&nbsp; &nbsp; mux.Lock()&nbsp; &nbsp; if _, isExist := mux.m[i]; isExist {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal("race condition")&nbsp; &nbsp; }&nbsp; &nbsp; mux.m[i] = true&nbsp; &nbsp; mux.Unlock()&nbsp; &nbsp; mux.Done()}这是因为无法保证另一个 goroutine 会更改 RUnlock 和 Lock 之间的映射。在您的示例中,您正在 goroutine 之间共享一个映射。这意味着您必须使用互斥体来保护对它的所有访问。如果你这样做,就不会围绕该地图的使用进行数据竞争。然而,一般来说,如果你能避免共享内存,你的程序就不会出现这样的数据竞争。
打开App,查看更多内容
随时随地看视频慕课网APP