golang:死锁可能发生在编译期?

问题描述 投票:0回答:1

我正在尝试用 golang 实现

Iterator
。 我这样写了
Iterator
界面:

type Iterator[Item any] interface {
    HasNext() bool
    Next() Item
    Iter() Iter[Item, Iterator[Item]]
}

另外,我定义了

Iter
来包裹
Iterator

type Iter[I any, T Iterator[I]] struct {
    Iter T
}

func New[I any, T Iterator[I]](iter T) Iter[I, T] {
    return Iter[I, T]{
        Iter: iter,
    }
}

然后我定义了一个

Vector
来测试我的迭代器,代码的一部分:

type Vector[Item any] struct {
    data []Item

    // used by iterator.
    idx int
}

func (v *Vector[Item]) Get(pos int) Item {
    if pos < 0 || pos >= v.Size() {
        panic("ouf off range")
    }

    return v.data[pos]
}

func (v *Vector[Item]) HasNext() bool {
    return v.idx < v.Size()
}

func (v *Vector[Item]) Next() Item {
    v.idx = v.idx + 1

    return v.Get(v.idx - 1)
}

func (v *Vector[Item]) Iter() iterator.Iter[Item, iterator.Iterator[Item]] {
    return iterator.Iter[Item, iterator.Iterator[Item]]{
        Iter: v,
    }
}

最后我运行这段代码:

func main() {
    s := vector.New[int]()
    println(s)
}

但是我遇到了死锁,堆栈的一些信息:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [sync.Mutex.Lock]:
sync.runtime_SemacquireMutex(0xbbbf60?, 0xc0?, 0xc0000c93e5?)
    runtime/sema.go:77 +0x25
sync.(*Mutex).lockSlow(0xc0003c9608)
    sync/mutex.go:171 +0x15d
sync.(*Mutex).Lock(...)
    sync/mutex.go:90
cmd/compile/internal/types2.(*Named).resolve(0xc0003c95e0)
    cmd/compile/internal/types2/named.go:164 +0x6c
cmd/compile/internal/types2.(*Named).TypeParams(...)
    cmd/compile/internal/types2/named.go:310 ... cmd/compile/internal/types2.(*Checker).checkFiles(0xc0001401e0, {0xc00009ea00, 0x2, 0x2})
    cmd/compile/internal/types2/check.go:371 +0x21e
cmd/compile/internal/types2.(*Checker).Files(...)
    cmd/compile/internal/types2/check.go:332
cmd/compile/internal/types2.(*Config).Check(0xc0003bfc80, {0xc0000c2030?, 0x127e540?}, {0xc00009ea00, 0x2, 0x2}, 0xc0003bfce0)
    cmd/compile/internal/types2/api.go:437 +0x14f
cmd/compile/internal/noder.checkFiles({0x0, {0x0, 0x0}}, {0xc00009e6c0, 0x2, 0x18?})
    cmd/compile/internal/noder/irgen.go:70 +0x486
cmd/compile/internal/noder.writePkgStub({0x0?, {0x0?, 0x0?}}, {0xc00009e6c0, 0x2, 0x2})
    cmd/compile/internal/noder/unified.go:210 +0x6a
cmd/compile/internal/noder.unified({0x0?, {0x0?, 0x0?}}, {0xc00009e6c0?, 0xb88540?, 0xc0000cb8f8?})
    cmd/compile/internal/noder/unified.go:75 +0x85
cmd/compile/internal/noder.LoadPackage({0xc0000d4120, 0x2, 0xe})
    cmd/compile/internal/noder/noder.go:77 +0x450
cmd/compile/internal/gc.Main(0xc74ae0)
    cmd/compile/internal/gc/main.go:198 +0xc17

但是为什么呢?我测试了一下,发现问题出在接口中的Iter方法及其在Vector中的实现。
当它们同时存在时就会出现死锁,我推测死锁可能发生在编译时。
我不太擅长泛型,你能给我一些更好的建议吗?
谢谢您的回答!(,,€^€,,)

go generics deadlock
1个回答
0
投票

我之前发现了与您在评论中引用的问题@jub0bs所遇到的相同恐慌相关的类似问题(感谢您的链接和引用顺便说一句):

fatal error: all goroutines are asleep - deadlock!

这是由递归引用泛型类型引起的,当您想要返回泛型类型作为其父泛型类型时,通常可以重现。我制作了一个完整的复制存储库,其中包含所有不应该发生的行为(除了我们是否应该编写这样的泛型代码),当我尝试调查此类问题并尝试向 Golang 团队报告时,您可能需要采取行动看看它。

虽然 Golang 团队成员已将其识别为与包中的实现和检查相关的编译器错误

type2
,而像
fatal error
这样的恐慌不应该只发生在某些行为不稳定和不一致的情况下, Golang团队成员也纷纷表示,这样的定义确实是禁止的,也是不允许的。

我的建议是,您可能需要考虑使用另一种方法将迭代器方法实现为参数传递模式,而不是基于接收器的(或链式调用,如果您愿意的话)。

© www.soinside.com 2019 - 2024. All rights reserved.