gpt4 book ai didi

golang 中的递归在使用 goroutines、channels 和 sync.Waitgroup 时会产生死锁或负 WaitGroup 计数器

转载 作者:IT王子 更新时间:2023-10-29 01:09:23 24 4
gpt4 key购买 nike

我正在尝试使用递归函数查找所有目录的列表。该函数的代码是

func FindDirs(dir string, nativePartitions []int64, wg *sync.WaitGroup, dirlistchan chan string) {
// defer wg.Done here will give negative waitgroup panic, commenting it will give negative waitgroup counter panic
fd, err := os.Open(dir)
if err != nil {
panic(err)
}
filenames, err := fd.Readdir(0)
if err != nil {
panic(err)
}

for _, i := range filenames {

var buff bytes.Buffer
buff.WriteString(dir)
switch dir {
case "/":
default:
buff.WriteString("/")
}

buff.WriteString(i.Name())
/*err := os.Chdir(dir)
if err != nil {
return err
}*/

t := new(syscall.Statfs_t)
err = syscall.Statfs(buff.String(), t)
if err != nil {
//fmt.Println("Error accessing", buff.String())
}
if checkDirIsNative(t.Type, nativePartitions) && i.IsDir(){
dirlistchan <- buff.String()
FindDirs(buff.String(), nativePartitions, wg, dirlistchan) //recursion happens here
} else {
//fmt.Println(i.Name(), "is not native")
}


}
}

在主函数中,我称它为

wg := new(sync.WaitGroup)
dirlistchan := make(chan string, 1000)
wg.Add(1)
go func() {
filtermounts.FindDirs(parsedConfig.ScanFrom, []int64{filtermounts.EXT4_SUPER_MAGIC}, wg, dirlistchan)
}()


go func() {
wg.Wait()
close(dirlistchan)
}()
for i := range dirlistchan {
fmt.Println(i)
}
wg.Wait()

我得到了一个

fatal error: all goroutines are asleep - deadlock!

如果我打印结果而不是使用 channel ,或者使用互斥锁附加到 slice ,我就能够使它正常工作。 (用linux的find命令验证,看结果是否相同。)请在省略channels并使用sync.Mutex和append后找到函数。

func FindDirs(dir string, nativePartitions []int64, dirlist *[]string, mutex *sync.Mutex) []string{


fd, err := os.Open(dir)
defer fd.Close()
if err != nil {
panic(err)
}
filenames, err := fd.Readdir(0)
if err != nil {
panic(err)
}

for _, i := range filenames {
var buff bytes.Buffer
buff.WriteString(dir)
switch dir {
case "/":
default:
buff.WriteString("/")
}

buff.WriteString(i.Name())
/*err := os.Chdir(dir)
if err != nil {
return err
}*/

t := new(syscall.Statfs_t)
err = syscall.Statfs(buff.String(), t)
if err != nil {
//fmt.Println("Error accessing", buff.String())
}
if checkDirIsNative(t.Type, nativePartitions) && i.IsDir(){
//dirlistchan <- buff.String()
mutex.Lock()
*dirlist = append(*dirlist, buff.String())
mutex.Unlock()
//fmt.Println(buff.String())

FindDirs(buff.String(), nativePartitions, dirlist, mutex)
} else {
//fmt.Println(i.Name(), "is not native")
}

}
return *dirlist
}

但我想不出一种方法来使它与 channel 和 goroutine 一起工作。非常感谢任何帮助。

备注:Here是带有代码的 golang playground 的链接。我也找不到让系统调用的东西在 Playground 上工作的解决方法。不过它可以在我的系统上运行。

谢谢。

最佳答案

简答:您没有关闭 channel 。

修复:在调用 FindDirs

的 go 例程的开头添加 defer wg.Done()
go func() {
defer wg.Done()
filtermounts.FindDirs(parsedConfig.ScanFrom, []int64{filtermounts.EXT4_SUPER_MAGIC}, wg, dirlistchan)
}()

为什么会这样

负责关闭 channel 的go例程等待wg上面的代码中没有wg.Done。如此接近永远不会发生

现在 for 循环阻塞 channel 上的 close 或永远的值,这会导致错误

fatal error: all goroutines are asleep - deadlock!

所以这是你的代码,它可以运行为

go run filename.go /path/to/folder

代码

package main

import (
"bytes"
"fmt"
"os"
"sync"
"syscall"
)

func main() {

wg := new(sync.WaitGroup)
dirlistchan := make(chan string, 1000)
wg.Add(1)
go func() {
defer wg.Done()
FindDirs(os.Args[1], []int64{61267}, wg, dirlistchan)
}()

go func() {
wg.Wait()
close(dirlistchan)
}()
for i := range dirlistchan {
fmt.Println(i)
}
wg.Wait()

}

func FindDirs(dir string, nativePartitions []int64, wg *sync.WaitGroup, dirlistchan chan string) {
fd, err := os.Open(dir)
if err != nil {
panic(err)
}
filenames, err := fd.Readdir(0)
if err != nil {
panic(err)
}

for _, i := range filenames {

var buff bytes.Buffer
buff.WriteString(dir)
switch dir {
case "/":
default:
buff.WriteString("/")
}

buff.WriteString(i.Name())
/*err := os.Chdir(dir)
if err != nil {
return err
}*/

t := new(syscall.Statfs_t)
err = syscall.Statfs(buff.String(), t)
if err != nil {
//fmt.Println("Error accessing", buff.String())
}
if checkDirIsNative(t.Type, nativePartitions) && i.IsDir() {
dirlistchan <- buff.String()
FindDirs(buff.String(), nativePartitions, wg, dirlistchan) //recursion happens here
} else {
//fmt.Println(i.Name(), "is not native")
}

}
}

func checkDirIsNative(dirtype int64, nativetypes []int64) bool {
for _, i := range nativetypes {
if dirtype == i {
return true
}
}
return false
}

找到 go.play 链接 here

关于golang 中的递归在使用 goroutines、channels 和 sync.Waitgroup 时会产生死锁或负 WaitGroup 计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41447907/

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