go - 我怎样才能摆脱这种数据竞争

标签 go

我有这两个功能:

// PartyHub struct contains all data for the party
type PartyHub struct {
    FullPartys    map[string]Party
    PartialPartys map[string]Party
    Enter         chan Member
    Leave         chan Member
    sync.Mutex
}


// RemoveFromQueue will remove the member from party
func (p *PartyHub) RemoveFromQueue(memberLeaving Member, inQueue bool) {
    if !inQueue {
        return
    }
    for _, party := range p.PartialPartys {
        go func(party Party) {
            if _, ok := party.Members[memberLeaving.Identifier]; ok {
                p.Lock()
->>>>>>>>       delete(party.Members, memberLeaving.Identifier)
                p.Unlock()
            }
        }(party)
    }
    log.Println("Removing")
}

// SortIntoParty will sort the member into party
func (p *PartyHub) SortIntoParty(newMember Member, inQueue bool) {
    log.Println(inQueue)
    if inQueue {
        return
    }
    log.Println("Adding")
    foundParty := false
->> for partyid, party := range p.PartialPartys {
        if !party.Accepting {
            continue
        }

        goodFitForParty := true
        for _, partyMember := range party.Members {
            if newMember.Type == partyMember.Type && newMember.Rank >= partyMember.Rank-partyMember.RankTol && newMember.Rank <= partyMember.Rank+partyMember.RankTol {
                goodFitForParty = true
                continue
            } else {
                goodFitForParty = false
                break
            }
        }

        if !goodFitForParty {
            continue
        } else {
            foundParty = true
            newMember.Conn.CurrentParty = partyid
            p.Lock()
            p.PartialPartys[partyid].Members[newMember.Conn.Identifier] = newMember
            p.Unlock()
            if len(party.Members) == 2 {
                p.Lock()
                party.Accepting = false
                p.Unlock()
                // Start Go Routine
            }
            break
        }
    }
    if !foundParty {
        uuid := feeds.NewUUID().String()
        newMember.Conn.CurrentParty = uuid
        p.Lock()
        p.PartialPartys[uuid] = Party{Accepting: true, Members: make(map[string]Member), Ready: make(chan *Connection), Decline: make(chan *Connection)}
        p.PartialPartys[uuid].Members[newMember.Conn.Identifier] = newMember
        p.Unlock()
    }
}

我将 ->>>>>> 放在访问 2 段代码的位置旁边,我不确定如何在不在数据中的情况下使这 2 段保持最新种族,相当新,想知道我应该如何在没有数据竞争的情况下读写这个变量。

最佳答案

你的问题中有很多代码,但看起来你正试图从一个 goroutine 中的 map (party.Members) 中删除元素,同时循环遍历它其他。这听起来像是一场无法维护、错误百出的灾难,但没有内存竞争是可能的。

您需要一个互斥锁来保护对 map 的访问(读取和写入),而困难的部分是确保在 for/range 迭代期间保持锁定。这是一种方法,在 for 循环开始之前持有锁,然后在循环体内解锁。

var mut sync.Mutex
var m = map[string]int{}

func f(key string) {
    mut.Lock()
    defer mut.Unlock()
    delete(m, key)
}

func g() {
    mut.Lock()
    defer mut.Unlock()
    for k, v := range m {
        mut.Unlock()
        fmt.Println(k, v)
        mut.Lock()
    }
}

在这里,可以同时调用 fg 的任意组合,而不会发生内存竞争。

更容易理解的是不解锁/锁定循环内的互斥量,这意味着 f 中的删除将等待 g 中的任何正在运行的循环完成(或反之亦然)。

关于go - 我怎样才能摆脱这种数据竞争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34469080/

相关文章:

json - Golang 中的语法错误

go - 尝试呈现模板,出现错误 html/template : "templates/index.html" is undefined

go - 使用 `didip/tollbooth` 限制每小时最大请求数

go - 构建 Go 应用程序

go - 无法使用 go 打印/查找 mongo_db 的记录数

go - 修改原生 Golang 包后如何重建它们?

go - 我如何在 GORM(Golang) 中进行表锁定?

macos - 更新到 macOS beta 4 后,go test -cover 抛出 "fatal error: unexpected signal during runtime execution"

Go接收器隐式指针转换不起作用

go - 好的意味着什么,如果循环