gpt4 book ai didi

multithreading - 所有goroutines死锁

转载 作者:行者123 更新时间:2023-12-03 10:11:04 28 4
gpt4 key购买 nike

遇到所有 goroutine 都处于休眠状态的问题 - 死锁。
我有一个带有汽车数组的数据结构,其中的汽车数量有限。如果数组中没有汽车并且主线程尚未完成将数据写入数据结构,则工作线程启动并尝试从数据结构中删除汽车,然后工作线程休眠,直到主线程将更多汽车添加到数据结构汽车数组中。然后工作线程唤醒,从数据结构中删除汽车对象,进行计算并将其移动到结果结构中。在某些时候,它有时会陷入僵局。注意到即使程序毫无异常(exception)地完成,一些数据(有时更多,有时更少)仍然丢失。
代码:

    package main

import (
"crypto/sha256"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strconv"
"sync"
)

type Car struct {
Make string `json:"Make"`
Year int `json:"Year"`
Displacement float64 `json:"Displacement"`
Hash string
}
type Cars struct {
Auto []Car
count int
MaxLen int
mutex *sync.Mutex
cond *sync.Cond
end bool
}

func (a *Cars) Insert(aut Car) {
a.mutex.Lock() // lock method so other thread couldin't use Data structure
for a.count == a.MaxLen {
a.cond.Wait()//wait if current count of cars is equal to maximum amount that are allowed to store in cars array in Data structure
}

a.Auto[a.count] = aut
a.count++
a.mutex.Unlock()
a.cond.Broadcast()
}

func (a *Cars) Remove(group *sync.WaitGroup) Car {
a.mutex.Lock()
for a.count == 0 {
a.cond.Wait()//if there is no cars to remove from Data struct car array then sleep
}
result := a.Auto[a.count-1]//get the last car from cars structure car array
var tmp Car
a.Auto[a.count-1] = tmp//remove the last car from structure car array
a.count--

a.mutex.Unlock() // unlock this method and let others thread use i
a.cond.Broadcast() //tell all threads that removing has been finishedt
return result
}
func (a *Cars) InsertSort(aut Car) {
a.mutex.Lock()
for a.count == a.MaxLen {
a.cond.Wait()
}
j := 0
for i := 0; i < a.count; i++ {
if a.Auto[i].Displacement < aut.Displacement {
j = i //Finds where to insert new item in sorted list
}
}
if j != 0 {
for i := a.count; i >= j; i-- {
a.Auto[i+1] = a.Auto[i]//moves objects from j to the right
}
}
a.Auto[j] = aut
a.count++
a.mutex.Unlock()
a.cond.Broadcast()
}

var Auto []Car

func main() {
CurrentWD, err := os.Getwd()
if err != nil {
log.Println(err)
}
path := CurrentWD + "\\Auto.json"

jsonFile, err := os.Open(path)

byteValue, _ := ioutil.ReadAll(jsonFile)
json.Unmarshal(byteValue, &Auto)

var mutex = sync.Mutex{}
var cond = sync.NewCond(&mutex) //syncing cond with mutex
MaxLength := 5 // max lenght of data array
var A = make([]Car, 5)
Auto1 := Cars{count: 0, MaxLen: MaxLength, cond: cond, mutex: &mutex, Auto: A}//data structs

var B = make([]Car, 40)
Auto2 := Cars{count: 0, MaxLen: 40, cond: cond, mutex: &mutex, Auto: B}//results struct

var waitGroup = sync.WaitGroup{}

ThreadsAmt := 8

waitGroup.Add(ThreadsAmt)
for i := 0; i < ThreadsAmt; i++ {
go execute(&Auto1, &waitGroup, &Auto2)
}
for _, s := range Auto {
Auto1.Insert(s)
}

Auto1.end = true//finished writing to data struct
waitGroup.Wait()

var RLoc = CurrentWD + "\\Results.txt"
f, err := os.Create(RLoc)
defer f.Close()
f.WriteString(fmt.Sprintf("%15s|%4s|%12s|%50s \n", "Make", "Year", "Displacement", "Hash"))
for i := 0; i < Auto2.count-1; i++ {
f.WriteString(fmt.Sprintf("%3d %15s|%4d|%12.2f|%50s \n", i, Auto2.Auto[i].Make,
Auto2.Auto[i].Year, Auto2.Auto[i].Displacement, Auto2.Auto[i].Hash))
}

fmt.Println("Program finished execution")
}
func execute(Data *Cars, group *sync.WaitGroup, res *Cars) {
hash := sha256.New()
for Data.end == false && Data.count != 0 {
carTemp := Data.Remove(group)//removes and returns car object from data struct
if carTemp.Displacement > 0 {//checks if returned car object displacement is bigger than *
var ss string
ss = carTemp.Make + strconv.Itoa(carTemp.Year) + fmt.Sprint(carTemp.Displacement) //making string calculating hash
sum := hash.Sum([]byte(ss))
for i := 0; i < len(sum); i++ {
ss += string(sum[i])//joining hash byte array in to string
}
carTemp.Hash = ss
res.InsertSort(carTemp) // inserts car
}
}
defer group.Done()
}
数据:Auto.json
[{
"Make": "Chrysler",
"Year": 1997,
"Displacement": 3.6
}, {
"Make": "Honda",
"Year": 2016,
"Displacement": 1.4
}, {
"Make": "Aston Martin",
"Year": 2009,
"Displacement": 4.1
}, {
"Make": "Geo",
"Year": 2011,
"Displacement": 4.9
}, {
"Make": "Buick",
"Year": 2001,
"Displacement": 6.3
}, {
"Make": "Chevrolet",
"Year": 2001,
"Displacement": 2.7
}, {
"Make": "Suzuki",
"Year": 2004,
"Displacement": 4.5
}, {
"Make": "Studebaker",
"Year": 2001,
"Displacement": 7.5
}, {
"Make": "Chevrolet",
"Year": 2020,
"Displacement": 1.1
}, {
"Make": "Volkswagen",
"Year": 1996,
"Displacement": 6.2
}, {
"Make": "Mercedes-Benz",
"Year": 2009,
"Displacement": 2.9
}, {
"Make": "Nissan",
"Year": 2019,
"Displacement": 7.2
}, {
"Make": "Subaru",
"Year": 2010,
"Displacement": 2.6
}, {
"Make": "Hummer",
"Year": 1991,
"Displacement": 8.8
}, {
"Make": "Subaru",
"Year": 2017,
"Displacement": 8.0
}, {
"Make": "Mitsubishi",
"Year": 2010,
"Displacement": 6.6
}, {
"Make": "Mercedes-Benz",
"Year": 1996,
"Displacement": 2.0
}, {
"Make": "Lincoln",
"Year": 1991,
"Displacement": 9.9
}, {
"Make": "Chevrolet",
"Year": 1998,
"Displacement": 3.4
}, {
"Make": "Dodge",
"Year": 2010,
"Displacement": 5.8
}, {
"Make": "GMC",
"Year": 2016,
"Displacement": 6.8
}, {
"Make": "Chevrolet",
"Year": 2013,
"Displacement": 3.4
}, {
"Make": "Ford",
"Year": 2010,
"Displacement": 5.1
}, {
"Make": "Toyota",
"Year": 2017,
"Displacement": 9.6
}, {
"Make": "Hyundai",
"Year": 2015,
"Displacement": 3.8
}, {
"Make": "Mercedes-Benz",
"Year": 2016,
"Displacement": 4.3
}, {
"Make": "Chevrolet",
"Year": 2019,
"Displacement": 2.2
}, {
"Make": "Dodge",
"Year": 2009,
"Displacement": 1.8
}, {
"Make": "Pontiac",
"Year": 2006,
"Displacement": 4.6
}, {
"Make": "Chevrolet",
"Year": 2008,
"Displacement": 9.2
}]
错误:
fatal error :所有 goroutine 都处于休眠状态 - 死锁!
goroutine 1 [sync.Cond.Wait]:
runtime.goparkunlock(...)
E:/Program Files (x86)/Go projects/go1.15.2/src/runtime/proc.go:312
sync.runtime_notifyListWait(0xc00003c050, 0x3)
E:/Program Files (x86)/Go projects/go1.15.2/src/runtime/sema.go:513 +0x117
sync.(*Cond).Wait(0xc00003c040)
E:/Program Files (x86)/Go projects/go1.15.2/src/sync/cond.go:56 +0xa5
main.(*Cars).Insert(0xc00003c080, 0xc000014343, 0x3, 0x7e0, 0x401b333333333333, 0x0, 0x0)
c:/Users/Justas/OneDrive - Kaunas University of Technology/5
Semestras/Lygiagretusis programavimas/Lab1/main.go:32 +0x57
main.main()
c:/Users/Justas/OneDrive - Kaunas University of Technology/5
Semestras/Lygiagretusis programavimas/Lab1/main.go:109 +0x53c
exit status 2
Process exiting with code: 1 signal: false

最佳答案

欢迎来到 StackOverflow 和 Go 开发!围棋货币很强大——但也很难掌握。不要气馁!
问题:

  • 而其他函数使用 sync 锁定 - execute() 函数没有 - 导致大量数据竞争条件
  • 编译数据竞争版本 go build --race 和标准错误将显示并发读/写发生的位置。阅读 more here

  • InsertSort 功能在很多边缘情况下被破坏
  • 使用哈希不正确:
  • 创建哈希,写入字节,然后通过 h.Sum(nil) 计算哈希
  • 散列是二进制的 - 因此在使用 fmt 十六进制格式打印它们时,建议使用。 ( %x )


  • 设计:
  • 正如@Adrian 提到的 - 使用 channel 更容易协调 - 在输入工作项目时。 slice 在这里控制并发访问很乏味
  • 您的输出需要排序 slice - 因此在这种情况下,结果 channel 没有意义。
  • Go slice 已经有一个计数,您可以使用 native len() 函数检索 - 因此无需使用您自己的 count 字段
  • 跟踪长度
  • 减少 slice 长度时, slice 条目不需要清零
  • 删除 slice 的最后一个元素:s = s[:len(s)-1]

  • 有太多古怪的 slice 操作来确定死锁的原因
  • 去标准库有 sort.Slice 为你做繁重的工作

  • 我应用了上述所有建议并将它们滚动到基于 channel 的解决方案中 - 在输出 slice 上使用互斥锁,以便在运行时对结果进行排序:
    https://play.golang.org/p/ewR3zHxirL8
    这可以通过让工作人员将结果写入输出 channel 来改善 - 并让结果 goroutine 读取该 channel ,因此在最后只排序一次。这消除了对任何 sync.Mutex 和任何自定义结构的需要:
    https://play.golang.org/p/0T1fFaP0iml

    关于multithreading - 所有goroutines死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64234386/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com