Беги и используй SDL в Goroutine на ходу - PullRequest
1 голос
/ 08 мая 2019

У меня есть программа с несколькими множественными циклами, каждый из которых выполнялся в Goroutine. Мне нужно подключить или отключить мониторы во время работы моей программы, поэтому мне нужно перезапустить sdl, чтобы он смог найти мои новые мониторы, я делаю это с помощью sdl.quit (), чтобы выйти из последних sdl и sdl.init (sdl.InitEverything) чтобы инициализировать его снова. Моя проблема в том, что я должен обрабатывать события sdl в цикле. Если я этого не сделаю, он перестанет отвечать на запросы, но этот цикл заблокирует мой основной код. Мне не нужно обрабатывать какие-либо события, такие как щелчки мышью, я просто хочу показать простую картинку и манипулировать ими, есть ли способ остановить события или запустить весь 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)
}

В моей главной функции я говорю ему запустить sdl и через 5 секунд закрыть все и подождать 15 секунд, но окно не закрывается.

1 Ответ

3 голосов
/ 08 мая 2019

Будьте осторожны, так как использование SDL из нескольких потоков не совсем тривиально.Как правило, ваш цикл SDL должен находиться в потоке main.Для этого есть веская причина: цикл обработки событий является частью потока main, и многие ваши объекты создаются и изменяются в потоке main ... или, по крайней мере, так и должно быть.

Когда вы вводите несколько потоков, может произойти странное неопределенное и опасное поведение.Вот почему хорошее правило - использовать runtime.LockOSThread, чтобы среда выполнения Go не прикрепляла вашу main программу к другим потокам и сохраняла ее в потоке main.

См. Это дляподробнее: введите описание ссылки здесь

...