golang qml (go-qml) аргумент cgo имеет указатель Go на указатель Go
Привет, я использую библиотеку qml для создания пользовательских интерфейсов. Я пытаюсь научиться передавать информацию из пользовательского интерфейса (qml), чтобы потом "что-то делать". QML работает, если это просто пользовательский интерфейс. Я могу запустить это нормально, когда я делаю:
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: %v\n", 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
}
Однако, когда я добавляю некоторый код, чтобы попытаться "изучить" что-то из пользовательского интерфейса, я получаю ошибку времени выполнения:
паника: ошибка во время выполнения: аргумент cgo имеет указатель Go на указатель Go
Код, который я добавляю:
window.On("visibleChanged", func(visible bool) {
if (visible) {
fmt.Println("Width:", window.Int("width"))
}
})
Я использую "go version go1.6 darwin/amd64" на OSX El Capitan
Есть идеи почему? Google предполагает, что это было ошибкой в Go 1.6 Beta, но у меня установлена последняя стабильная версия (установлена пару дней назад).
Если это не простое исправление, может кто-нибудь объяснить, почему это происходит?
3 ответа
Если вы просто играете вокруг, я предлагаю попробовать перейти с версии 1.5.3. Go 1.6 ввел другой набор ограничений для указателей на память при использовании cgo, более ограниченный набор, и возможно, что некоторые пакеты go, которые были разработаны для более старой версии go, теперь нарушают правило go или два.
Если это так, заставить старый пакет работать с go 1.6, где C разрешено вызывать замыкания go, может быть сложнее исправить. Но у меня пока нет личного опыта с этим.
Проблема заключается в том, что когда код 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". Причина, по которой это не разрешено, заключается в том, что эти указатели труднее защитить от GC на время вызова C, и это того не стоит, поэтому вместо этого это запрещено ( https://github.com/golang/go/issues/12416). Однако, даже если бы это было разрешено, код все равно нарушал бы правило о том, что в коде C сохраняется копия указателя Go. На самом деле это не проблема в Go 1.6, так как он не реализует движущийся сборщик мусора, но правила были сделаны так, чтобы его можно было реализовать позже.
Спасибо за всю помощь здесь. Я написал учебник для начинающих по использованию QML с Go. Это можно посмотреть здесь. Я буду постоянно обновлять его, если столкнусь с какими-либо еще ошибками и найду исправления. Спасибо всем за вашу помощь. QML/GO - отличная комбинация.