golang qml (go-qml) cgo 参数具有 Go 指向 Go 指针的指针



嗨,我正在使用 qml 库来创建 UI。我正在尝试学习如何从 UI (qml( 传递信息,然后"做某事"。如果 QML 只是一个 UI,它就可以工作。当我这样做时,我可以运行得很好:

func main() {
    if len(os.Args) != 2 {
        fmt.Fprintf(os.Stderr, "usage: %s <qml file>n", os.Args[0])
        os.Exit(1)
    }
    if err := qml.Run(run); err != nil {
        fmt.Fprintf(os.Stderr, "error: %vn", err)
        os.Exit(1)
    }
}
func run() error {
    engine := qml.NewEngine()
    engine.On("quit", func() { os.Exit(0) })
    component, err := engine.LoadFile(os.Args[1])
    if err != nil {
        return err
    }
    window := component.CreateWindow(nil)
    window.Show()
    window.Wait()
    return nil
}

但是,当我添加一些代码时,要尝试从 UI 中"学习"一些东西,我会收到运行时错误:

panic:运行时错误:cgo 参数具有 Go 指针到 Go 指针

我添加的代码是:

window.On("visibleChanged", func(visible bool) {
    if (visible) {
            fmt.Println("Width:", window.Int("width"))
    }
})

我在OSX El Capitan上运行"go版本go1.6 darwin/amd64">

知道为什么吗?谷歌建议这是Go 1.6 Beta中的一个错误,但我正在运行最新的稳定版本(几天前安装(。

如果这不是一个简单的修复,有人可以解释"为什么"会发生这种情况吗?

问题是,当 C 代码存储 Go 指针(在本例中为指向回调函数的指针(时,垃圾回收器无法在 C 代码中跟踪该指针,并且如果没有 Go 代码引用指针指向的内存,则可能会对指针指向的内存进行垃圾回收。这将导致 C 代码在尝试访问该内存时崩溃。运行时只知道 C 代码保留了指针(这就是为什么它会死机(,但它不知道 C 代码稍后会如何处理它以及它会保留多长时间。

为了避免这种情况,大多数库使用的技巧是在 Go 中也保留一个指针(例如在全局映射中(,以确保内存受到垃圾回收器保护。 Go-QML也使用这个技巧。这个技巧有效,但编译器和垃圾收集器不知道它确实有效,他们无法验证您没有犯错误(例如,删除 Go 指针,而 C 代码仍然有其指针(。

在 Go 1.6 中,Go 开发人员决定对此非常严格,他们不再允许 C 代码保留 Go 指针。但是,如果您禁用此检查,在这种情况下一切仍然可以正常工作,因为 go-qml 正确实现了该技巧(但是它将来可能会中断,例如,如果 go 实现了移动垃圾收集器(。

这是关于它的问题:https://github.com/go-qml/qml/issues/170

旁注:在这种特定情况下,传递给 C 的是指向 interface{} 的指针,它本身包含一个指向函数的指针。这就是为什么你得到错误"cgo 参数有 Go 指针到 Go 指针"。不允许这样做的原因是,在 C 调用期间保护这些指针免受 GC 的影响更加困难,而且不值得这样做,因此禁止这样做 (https://github.com/golang/go/issues/12416#issuecomment-136473697(。但是,即使允许这样做,代码仍然会违反有关 C 代码保留 Go 指针副本的规则。这在 Go 1.6 中实际上不是问题,因为它没有实现移动垃圾收集器,但制定了规则,以便以后可以实现。

如果你只是在玩,我建议尝试使用 go 1.5.3。 Go 1.6 在使用 cgo 时对指向内存的指针引入了一组不同的约束,这是一个限制性更强的集合,并且可能一些为旧版 go 设计的 go 包现在正在违反一两个 go 规则。

如果是这种情况,让较旧的包与 go 1.6 一起工作,其中允许 C 调用 go 闭包,可能更难修复。 但我还没有第一手经验。

感谢这里的所有帮助。我写了一个关于在 Go 中使用 QML 的初学者教程。可以在这里查看。如果我遇到更多错误并找到修复程序,我将不断更新它。感谢大家的帮助。QML/GO是一个很棒的组合。

https://golog.co/blog/article/Using_Go_with_QML_part_1

最新更新