gpt4 book ai didi

opengl - Golang fmt.Println() 导致游戏崩溃

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

我在 Go 中有这个简单的 OpenGL 程序。

当我编译并运行它时,主游戏循环在因分段违规而崩溃之前经历了大约 9 次迭代。

rendering for the  0  time
rendering for the 1 time
rendering for the 2 time
rendering for the 3 time
rendering for the 4 time
rendering for the 5 time
rendering for the 6 time
SIGSEGV: segmentation violation
PC=0x7fdab95a0e29
signal arrived during cgo execution

runtime.cgocall(0x414f90, 0x7fdab9887e88)
/usr/lib/go/src/pkg/runtime/cgocall.c:149 +0x11b fp=0x7fdab9887e70
github.com/go-gl/gl._Cfunc_glClear(0xc200004100)
github.com/go-gl/gl/_obj/_cgo_defun.c:340 +0x31 fp=0x7fdab9887e88
github.com/go-gl/gl.Clear(0x4100)
/mnt/data/Dropbox/Coding/Go/src/github.com/go-gl/gl/gl.go:161 +0x25 fp=0x7fdab9887e98
main.draw()
/home/josh/Coding/Go/src/github.com/JoshWillik/Wander/wander.go:120 +0x25 fp=0x7fdab9887eb8
main.main()
/home/josh/Coding/Go/src/github.com/JoshWillik/Wander/wander.go:52 +0x300 fp=0x7fdab9887f48
runtime.main()
/usr/lib/go/src/pkg/runtime/proc.c:220 +0x11f fp=0x7fdab9887fa0
runtime.goexit()
/usr/lib/go/src/pkg/runtime/proc.c:1394 fp=0x7fdab9887fa8

goroutine 3 [syscall]:
runtime.goexit()
/usr/lib/go/src/pkg/runtime/proc.c:1394

rax 0x0
rbx 0x7fdab9887e88
rcx 0x7fdab9887e88
rdx 0x7fdab9887e20
rdi 0x4100
rsi 0xc210001900
rbp 0xc21002a000
rsp 0x7fdab2a4ddd8
r8 0xc210001120
r9 0x7fdab9887e20
r10 0x0
r11 0x286
r12 0x0
r13 0x7fdab9a74000
r14 0x0
r15 0x7fdab2a4e700
rip 0x7fdab95a0e29
rflags 0x10202
cs 0x33
fs 0x0
gs 0x0

如果我删除 shouldRender 函数中的基于时间的逻辑,它会在崩溃前进行大约 28-29 次迭代。

如果我在 draw 函数中删除对 gl.Clear() 的调用,它会在崩溃前持续到 90 年代。

如果我在 shouldRender 中删除对 fmt.Println() 的调用,游戏将按预期运行而不会崩溃。 (我已经测试了大约 2 或 3 分钟,所以将近 10,000 帧)

这让我怀疑对 fmt.Println() 的调用在某种程度上导致了分段违规。我误读了这些标志吗?如果不是,像 Println() 这样的核心函数怎么会这么不稳定?

package main

import (
f "fmt"
"github.com/go-gl/gl"
glfw "github.com/go-gl/glfw3"
"math"
"time"
)

var (
numRendered = 0
lastDraw = time.Now()
fps = 60
seconds = time.Now()
attr gl.AttribLocation
)

func main(){
if !glfw.Init(){
f.Println("Failed to init glfw")
panic("Cannot initialize glfw library")
}
defer glfw.Terminate()

//glfw.WindowHint(glfw.DepthBits, 16)
window, err := glfw.CreateWindow(300, 300, "Wander", nil, nil)
if err != nil{
panic(err)
}

window.SetFramebufferSizeCallback(reshape)
window.SetKeyCallback(key)
window.MakeContextCurrent()
glfw.SwapInterval(1)
width, height := window.GetFramebufferSize()
reshape(window, width, height)

if gl.Init() != 0 {
panic("Failed to init GL")
}

prog := setupProgram()
defer prog.Delete()
prog.Use()

attr = prog.GetAttribLocation("offset")

setup()
for !window.ShouldClose() {
if shouldRender(){
draw()
}
animate()
window.SwapBuffers()
glfw.PollEvents()
}
}
func setupProgram()(prog gl.Program){
vertexSource := `
#version 430 core

layout (location = 0) in vec4 offset;

const vec4 vertecies[3] = vec4[3](
vec4(0.25, 0.5, 0.5, 1.0),
vec4(-0.25, 0.5, 0.5, 1.0),
vec4(-0.25, -0.5, 0.5, 1.0)
);

void main(){
gl_Position = vertecies[gl_VertexID] + offset;
}`
fragmentSource := `
#version 430 core

out vec4 color;

void main(){
color = vec4(1.0, 0.0, 0.0, 0.0); // red, blue, green, ??
}`
vert, frag := gl.CreateShader(gl.VERTEX_SHADER), gl.CreateShader(gl.FRAGMENT_SHADER)
defer vert.Delete()
defer frag.Delete()
vert.Source(vertexSource)
frag.Source(fragmentSource)
vert.Compile()
frag.Compile()

prog = gl.CreateProgram()
prog.AttachShader(vert)
prog.AttachShader(frag)
prog.Link()
prog.Use()
f.Println(prog.GetInfoLog())

return
}

func key(window *glfw.Window, k glfw.Key, s int, action glfw.Action, mods glfw.ModifierKey) {
if action != glfw.Press {
return
}

switch glfw.Key(k){
case glfw.KeyEscape:
window.SetShouldClose(true);
default:
return
}
}

func reshape(window *glfw.Window, width, height int){
gl.Viewport(0, 0, width, height)
}
func draw(){
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.DrawArrays(gl.TRIANGLES, 0, 3)
}
func shouldRender() bool{
if int(time.Since(lastDraw) * time.Second) >= 1000/fps{
//f.Println("rendering for the ", numRendered, " time")
numRendered++
lastDraw = time.Now()
return true
}

return false;
}

func animate(){
now := float64(time.Since(seconds))

offset := [4]float32{
float32(math.Sin(now)),
float32(math.Cos(now)),
0.0,0.0}
attr.Attrib4fv(&offset)

red := gl.GLclampf(math.Sin(now) * 0.25 + 0.75)
blue := gl.GLclampf(math.Cos(now) * 0.25 + 0.75)
green := gl.GLclampf(time.Since(seconds))
_ = green;

gl.ClearColor(red, blue, 0.2, 0.0)
}

最佳答案

我在我的机器上运行了您的代码——在 64 位 Windows 上运行 MinGW-w64。虽然我的带有 println 的代码运行的时间比你的长得多(崩溃前超过 30k 次调用),但我观察到相同的行为。

堆栈跟踪报告了对 gl 函数的调用,这给了我一个暗示:错误可能与 OpenGL 上下文有关。

确实,如果你加上

import (
//...
"runtime"
//...
)

和线

runtime.LockOSThread()

到 main 函数的顶部,错误消失了(或者至少在线程锁定的情况下它在我的机器上运行了几分钟,显然我无法证明它永远不会崩溃)。

当 Goroutines 被阻止执行某些任务(如 IO)时,Go 运行时会偶尔拆分额外的线程以保持程序运行。

我怀疑发生的事情是,有时在调用 Println 时,Goroutine 在系统调用中被阻塞,因此运行时通过在不同线程上运行主 goroutine 来“帮助”您。由于 OpenGL 上下文绑定(bind)到一个线程,这会导致您的程序在 GL 调用时崩溃,因为您在错误的线程上调用。

将 runtime.LockOSThread() 添加到 main 的顶部会强制主 Goroutine 始终在同一线程上执行,从而使所有 GL 调用保持在正确的上下文中。

我应该补充一点,我简要浏览了 fmt 包的源代码,从我所看到的,我无法证明 goroutine/thread 废话肯定会发生;但是,根据我对 Go 运行时的了解以及 LockOSThread 似乎修复它的事实,我强烈怀疑情况就是如此。

无论哪种方式:当您使用依赖于将上下文绑定(bind)到单个线程的 C 库(例如 OpenGL 或 OpenAL)时,请确保始终使用 runtime.LockOSThread 将其运行的 Goroutine 锁定到一个线程。

更新:我在 the Go scheduler 上找到了这份文件,如果我没看错的话,它证实了我的怀疑。诸如打印之类的系统调用可以调用要生成的新线程,以允许调用 goroutine 在程序被 IO 阻塞时继续。

关于opengl - Golang fmt.Println() 导致游戏崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21010854/

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