我在 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/
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
修改(澄清问题)我已经花了几天时间试图弄清楚如何从Facebook游戏中抓取特定信息;但是,我遇到了一堵又一堵砖墙。据我所知,主要问题如下。我可以使用Chrome的检查元素工具手动查找我需要的html-它似乎位于iframe中。但是,当我尝试抓取该iframe时,它是空的(属性除外):如果我使用浏览器的“查看页面源代码”工具,这与我看到的输出相同。我不明白为什么我看不到iframe中的数据。答案不是它是由AJAX之后添加的。(我知道这既是因为“查看页面源代码”可以读取Ajax添加的数据,也是因为我有b/c我一直等到我可以看到数据页面之后才抓取它,但它仍然不存在)。发生这种情况是因为
我正在尝试获得良好的Ruby编码风格。为防止意外调用具有相同名称的局部变量,我总是在适当的地方使用self.。但是现在我偶然发现了这个:classMyClass上面的代码导致错误privatemethodsanitize_namecalled但是当删除self.并仅使用sanitize_name时,它会起作用。这是为什么? 最佳答案 发生这种情况是因为无法使用显式接收器调用私有(private)方法,并且说self.sanitize_name是显式指定应该接收sanitize_name的对象(self),而不是依赖于隐式接收器(也是
下面的代码工作正常:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson)do|key,oldv,newv|ifkey==:aoldvelsifkey==:bnewvelsekeyendendputskerson.inspect但是如果我在“ifblock”中添加return,我会得到一个错误:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson
我有一个ruby脚本可以打开与Apple推送服务器的连接并发送所有待处理的通知。我看不出任何原因,但当Apple断开我的脚本时,我遇到了管道损坏错误。我已经编写了我的脚本来适应这种情况,但我宁愿只是找出它发生的原因,这样我就可以在第一时间避免它。它不会始终根据特定通知断开连接。它不会以特定的字节传输大小断开连接。一切似乎都是零星的。您可以在单个连接上发送的数据传输或有效负载计数是否有某些限制?看到人们的解决方案始终保持一个连接打开,我认为这不是问题所在。我看到连接在3次通知后断开,我看到它在14次通知后断开。我从未见过它能超过14点。有没有人遇到过这种类型的问题?如何处理?
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion是否有适用于这些的3d游戏引擎?
代码:threads=[]Thread.abort_on_exception=truebegin#throwexceptionsinthreadssowecanseethemthreadseputs"EXCEPTION:#{e.inspect}"puts"MESSAGE:#{e.message}"end崩溃:.rvm/gems/ruby-2.1.3@req/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:478:inload_missing_constant':自动加载常量MyClass时检测到循环依赖稍加研究后,
这些解析和执行良好:"=".scan(/=/)"=".scan(/=/)这会导致“未终止的正则表达式遇到文件结尾”:"=".scan/=/如果我在=之前插入一些内容,错误就会消失:"=".scan/^=/这是怎么回事? 最佳答案 我猜你正在点击thisintheparser:case'/':if(IS_BEG()){lex_strterm=NEW_STRTERM(str_regexp,'/',0);returntREGEXP_BEG;}if((c=nextc())=='='){set_yylval_id('/');lex_state