【问题标题】:Run and use SDL in a Goroutine in go在 Go 中的 Goroutine 中运行和使用 SDL
【发布时间】:2019-09-26 12:41:00
【问题描述】:

我有一个包含多个循环的程序,每个循环都在一个 Goroutine 中运行。我需要在程序运行时插入或拔出监视器,所以我必须重新启动 sdl 让它找到我的新监视器,我通过 sdl.quit() 来退出最后一个 sdl 和 sdl.init(sdl.InitEverything)再次初始化它。 我的问题是我必须在一个循环中处理 sdl 事件,如果我不这样做,它将变得无响应,但是这个循环会阻止我的主代码。我不需要处理鼠标点击之类的任何事件,我只想显示一些简单的图片并对其进行操作,有没有办法停止事件或在 goroutine 中运行整个 sdl?我试过但得到奇怪的结果。这是我的结构:

type SDLstruct{
    window *sdl.Window
    renderer *sdl.Renderer
    texture *sdl.Texture
    src, dst sdl.Rect
    event sdl.Event
    Close bool
    winWidth, winHeight int32
}

这个函数启动一个窗口和一个渲染器:

func (sdlVars *SDLstruct)StartWindow() (err error) {

    sdlVars.winWidth, sdlVars.winHeight = 1920,1080
    sdl.Init(sdl.INIT_VIDEO)
    Num,err :=sdl.GetNumVideoDisplays()
    if err!=nil {
        return err
    }
    var rect sdl.Rect
    rect,err = sdl.GetDisplayBounds(0)
    if err!=nil {
        return err
    }
    for i:=Num-1;i>=0;i--{
        Mod , _:=sdl.GetDisplayMode(i,0)
        if Mod.W ==info.winWidth && Mod.H==info.winHeight{
            rect,err = sdl.GetDisplayBounds(i)
            if err!=nil {
                return err
            }
            break
        }
    }
    sdlVars.window, err = sdl.CreateWindow(winTitle, rect.X, rect.Y,
        rect.W, rect.H, sdl.WINDOW_SHOWN)
    sdlVars.window.SetBordered(false)
    sdlVars.window.SetFullscreen(1)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", err)
        return err
    }
    sdlVars.renderer, err = sdl.CreateRenderer(sdlVars.window, -1, sdl.RENDERER_ACCELERATED)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Failed to create renderer: %s\n", err)
        return err
    }
    sdlVars.renderer.Clear()
    sdlVars.renderer.SetDrawColor(0, 0, 0, 255)
    sdlVars.renderer.FillRect(&sdl.Rect{0, 0, int32(info.winWidth), int32(info.winHeight)})
    sdlVars.renderer.Present()
    sdl.ShowCursor(0)
    return nil
}

这个函数处理事件:

func (sdlVars *SDLstruct)HandleEvents()  {
    for sdlVars.event = sdl.PollEvent(); sdlVars.event != nil; sdlVars.event = sdl.PollEvent() {
        switch t := sdlVars.event.(type) {
        case *sdl.QuitEvent:
            sdlVars.Close = true
        }
    }
}

这个关闭了一切:

func (sdlVars *SDLstruct)CloseSDL() (err error) {
    err =sdlVars.renderer.Destroy()
    if err!=nil{
        return err
    }
    err = sdlVars.window.Destroy()
    if err!=nil{
        return err
    }
    sdl.Quit()
    return nil
}

这是我的主要功能:

func main()  {
    var wg sync.WaitGroup
    SdlVars:= new(SDLstruct)
    wg.Add(1)
    go SdlVars.StartSDL()
    time.Sleep(time.Second*5)
    SdlVars.Close = true
    time.Sleep(time.Second*15)
}

在我的 Main 函数中,我告诉它启动 sdl 并在 5 秒后关闭所有内容并等待 15 秒,但它不会关闭窗口。

【问题讨论】:

  • “我试过了,但结果很奇怪。”你能定义“奇怪的结果”吗?
  • 有时有效。有时不是。有时它会在 5 秒后关闭窗口,但有时会在 10 秒后关闭。

标签: image go graphics sdl goroutine


【解决方案1】:

要小心,因为在多个线程中使用 SDL 并非完全无关紧要。通常,您的 SDL 循环必须位于 main 线程中。这是有充分理由的,因为事件循环是main 线程的一部分,并且您的许多对象都是在main 线程上创建和变异的……或者至少它们应该是。

当您引入多个线程时,可能会发生奇怪的未定义和危险行为。这就是为什么一个好的经验法则是使用 runtime.LockOSThread 来确保 Go 运行时不会将您的 main goroutine 固定到其他线程并将其保留在 main 线程上。

查看更多详情:enter link description here

【讨论】:

  • 如果我想要多线程,有什么解决方案吗?
  • 不,您当然可以这样做...但是您通常希望在其他线程上进行任何额外的计算和/或 io,然后进行必要的同步以最终将数据传输到主线程,所以您的 UI 可以正确更新。您需要将主线程视为专用于您的 UI 和事件循环,而其他线程可用于其他工作,但该工作必须以线程安全的方式正确“传递”给您的主线程。
  • 我将 sdl 保留在我的主线程中,并将其他人移动到其他线程并且它正在工作。
猜你喜欢
  • 1970-01-01
  • 2018-09-12
  • 2020-07-22
  • 1970-01-01
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
相关资源
最近更新 更多