Go在使用time.Tick时会导致OpenGL崩溃,但使用time.After则不会。

huangapple go评论84阅读模式
英文:

Go causes OpenGL to segfault with time.Tick but not time.After

问题

我有以下两个文件:

bridge.go:

package cube

// #cgo LDFLAGS: -lGL -lGLEW -lglfw
// #include <GLFW/glfw3.h>
// int init(GLFWwindow**);
// void render(GLFWwindow*);
import "C"

import (
	"fmt"
	"time"
)

func Init() {
	var window *_Ctype_GLFWwindow
	windowWat := (*[0]byte)(window)
	fmt.Printf("Calling init\n")
	if C.init(&windowWat) != 1 {
		return
	}
	window = (*_Ctype_GLFWwindow)(windowWat)

	//t := time.Tick(time.Second) // Doesn't work
	t := time.After(time.Second) // Works

	<-t
	fmt.Println("Rendering")
	C.render((*[0]byte)(window))

	select {}
}

cube.c:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#define INIT_WINDOW_W (800)
#define INIT_WINDOW_H (800)

void render(GLFWwindow* window) {
    glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 250.f / 254.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glfwSwapBuffers(window);
}

static void glfw_error(int errno, const char* description) {
    fprintf(stderr, "GLFW [%d] %s\n", errno, description);
    exit(1);
}

int init(GLFWwindow** window) {
    GLenum glewErr;

    glfwSetErrorCallback(glfw_error);
    if (!glfwInit()) {
        return 0;
    }

    *window = glfwCreateWindow(
        INIT_WINDOW_H,
        INIT_WINDOW_W,
        "wat",
        NULL,
        NULL
    );
    if (*window == NULL) {
        glfwTerminate();
        return 0;
    }

    glfwMakeContextCurrent(*window);

    glewErr = glewInit();
    if (glewErr != GLEW_OK) {
        fprintf(stderr, "glewInit failed: %s\n", glewGetErrorString(glewErr));
        return 0;
    }

    if (!GL_VERSION_2_0) {
        fprintf(stderr, "Don't have OpenGL >= 2.0\n");
        return 0;
    }

    return 1;
}

还有一个调用cube.Init()而不做其他操作的main.go文件。

我的问题出现在调用C.render之前的几行代码。如果我使用time.After,它可以正常工作,并显示一个蓝色的窗口。如果我使用time.Tick,它有时会显示一个黑色的窗口,有时会导致段错误。这个测试案例是从我的实际代码中大大简化而来的。

我有一种感觉是Go的调度器在某种程度上搞乱了事情,但我无法想出具体原因(或如何测试/修复)。我想知道是否有人有任何关于这个问题的想法,或者能否想出任何进一步调查的方法。

其他可能相关的信息:

  • Arch Linux,3.14.4-1-ARCH.x86_64
  • GLFW 3.0.4-1
  • GLEW 1.10.0-2
  • nVidia GeForce GTX 570M
  • nVidia驱动程序337.12-1
  • go1.2 linux/amd64

编辑:

这是段错误的消息:

SIGSEGV: segmentation violation
PC=0x7fda7d6a2e29
signal arrived during cgo execution

runtime.cgocall(0x401260, 0x7fda7d6f0e58)
        /opt/go/src/pkg/runtime/cgocall.c:149 +0x11b fp=0x7fda7d6f0e40
game/cube._Cfunc_render(0x24e13b0)
        game/cube/_obj/_cgo_defun.c:62 +0x31 fp=0x7fda7d6f0e58
game/cube.Init()
        /tmp/wat/cube/bridge.go:28 +0x156 fp=0x7fda7d6f0ee0
main.main()
        /tmp/wat/main.go:10 +0xac fp=0x7fda7d6f0f48
runtime.main()
        /opt/go/src/pkg/runtime/proc.c:220 +0x11f fp=0x7fda7d6f0fa0
runtime.goexit()
        /opt/go/src/pkg/runtime/proc.c:1394 fp=0x7fda7d6f0fa8

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

rax     0x0
rbx     0x24e13b0
rcx     0x7fda7d6f0e58
rdx     0x7fda7d6f0df0
rdi     0x24e13b0
rsi     0xc210001900
rbp     0xc21002a000
rsp     0x7fda76506dc8
r8      0xc210001120
r9      0x7fda7d6f0df0
r10     0x7fda76506ba0
r11     0x7fda7d6a2e20
r12     0x0
r13     0x7fda76507700
r14     0x0
r15     0x7fda76d07c80
rip     0x7fda7d6a2e29
rflags  0x10202
cs      0x33
fs      0x0
gs      0x0
exit status 2

看起来它在调用glClearColor时导致了段错误。

英文:

I have the following two files:

bridge.go:

package cube

// #cgo LDFLAGS: -lGL -lGLEW -lglfw
// #include &lt;GLFW/glfw3.h&gt;
// int init(GLFWwindow**);
// void render(GLFWwindow*);
import &quot;C&quot;

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func Init() {
	var window *_Ctype_GLFWwindow
	windowWat := (*[0]byte)(window)
	fmt.Printf(&quot;Calling init\n&quot;)
	if C.init(&amp;windowWat) != 1 {
		return
	}
	window = (*_Ctype_GLFWwindow)(windowWat)

	//t := time.Tick(time.Second) // Doesn&#39;t work
	t := time.After(time.Second) // Works

	&lt;-t
	fmt.Println(&quot;Rendering&quot;)
	C.render((*[0]byte)(window))

	select {}
}

cube.c:

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;GL/glew.h&gt;
#include &lt;GLFW/glfw3.h&gt;

#define INIT_WINDOW_W (800)
#define INIT_WINDOW_H (800)

void render(GLFWwindow* window) {
    glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 250.f / 254.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glfwSwapBuffers(window);
}

static void glfw_error(int errno, const char* description) {
    fprintf(stderr, &quot;GLFW [%d] %s\n&quot;, errno, description);
    exit(1);
}

int init(GLFWwindow** window) {
    GLenum glewErr;

    glfwSetErrorCallback(glfw_error);
    if (!glfwInit()) {
        return 0;
    }

    *window = glfwCreateWindow(
        INIT_WINDOW_H,
        INIT_WINDOW_W,
        &quot;wat&quot;,
        NULL,
        NULL
    );
    if (*window == NULL) {
        glfwTerminate();
        return 0;
    }

    glfwMakeContextCurrent(*window);

    glewErr = glewInit();
    if (glewErr != GLEW_OK) {
        fprintf(stderr, &quot;glewInit failed: %s\n&quot;, glewGetErrorString(glewErr));
        return 0;
    }

    if (!GL_VERSION_2_0) {
        fprintf(stderr, &quot;Don&#39;t have OpenGL &gt;= 2.0\n&quot;);
        return 0;
    }

    return 1;
}

As well as a main.go file which calls cube.Init() and nothing else.

My issue lies in the lines just before calling C.render. If I do a time.After, it works fine and displays a blue window as it's supposed to. If I do a time.Tick, it will rarely also display that blue window, but either display a black window or segfault. This test case is significantly boiled down from my actual code.

I have a feeling that go's scheduler is messing things up somehow, but I can't think how (or how to test/fix that). I'm curious if anyone has any ideas what's causing this, or can think of any ways to investigate further.

Other possibly significant information:

  • Arch linux, 3.14.4-1-ARCH.x86_64
  • GLFW 3.0.4-1
  • GLEW 1.10.0-2
  • nVidia GeForce GTX 570M
  • nVidia driver 337.12-1
  • go1.2 linux/amd64

EDIT:

Here's the segfault message:

SIGSEGV: segmentation violation
PC=0x7fda7d6a2e29
signal arrived during cgo execution

runtime.cgocall(0x401260, 0x7fda7d6f0e58)
        /opt/go/src/pkg/runtime/cgocall.c:149 +0x11b fp=0x7fda7d6f0e40
game/cube._Cfunc_render(0x24e13b0)
        game/cube/_obj/_cgo_defun.c:62 +0x31 fp=0x7fda7d6f0e58
game/cube.Init()
        /tmp/wat/cube/bridge.go:28 +0x156 fp=0x7fda7d6f0ee0
main.main()
        /tmp/wat/main.go:10 +0xac fp=0x7fda7d6f0f48
runtime.main()
        /opt/go/src/pkg/runtime/proc.c:220 +0x11f fp=0x7fda7d6f0fa0
runtime.goexit()
        /opt/go/src/pkg/runtime/proc.c:1394 fp=0x7fda7d6f0fa8

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

rax     0x0
rbx     0x24e13b0
rcx     0x7fda7d6f0e58
rdx     0x7fda7d6f0df0
rdi     0x24e13b0
rsi     0xc210001900
rbp     0xc21002a000
rsp     0x7fda76506dc8
r8      0xc210001120
r9      0x7fda7d6f0df0
r10     0x7fda76506ba0
r11     0x7fda7d6a2e20
r12     0x0
r13     0x7fda76507700
r14     0x0
r15     0x7fda76d07c80
rip     0x7fda7d6a2e29
rflags  0x10202
cs      0x33
fs      0x0
gs      0x0
exit status 2

And it appears to segfault at the call to glClearColor

答案1

得分: 2

将我的评论转化为答案:

由于某种原因,OpenGL通常要求所有内容在同一个操作系统线程中运行。time.Tick和time.After调用不同的运行时函数,其中一个可能导致不同的OpenGL调用在不同的线程中运行。默认情况下,Go语言不能保证goroutine在特定线程上运行。

要解决这个问题,你需要使用runtime.LockOSThread。这将确保只有该goroutine在当前线程上运行。

你可以在这里阅读更多相关主题的内容:https://groups.google.com/forum/#!topic/golang-nuts/5Pvv1Gr1eoo

英文:

Turning my comment into an answer:

For some reason OpenGL often requires everything run in the same OS thread. time.Tick and time.After call different runtime functions and one may be causing different opengl calls to run in separate threads. By default, Go makes does not guarantee a goroutine runs on a specific thread.

To fix this, you need to use runtime.LockOSThread. This will ensure that goroutine and only that goroutine ever run on the current thread.

You can read more on the topic here: https://groups.google.com/forum/#!topic/golang-nuts/5Pvv1Gr1eoo

huangapple
  • 本文由 发表于 2014年5月26日 12:01:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/23862499.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定