代码之家  ›  专栏  ›  技术社区  ›  user202729 Nati Keidar

用SDL2从C++ 11线程中可移植地退出读出线

  •  1
  • user202729 Nati Keidar  · 技术社区  · 6 年前

    考虑一个简单的程序:(需要 -std=c++11 -lpthread -lreadline -lSDL2 使用g++和pthread编译时)

    #include <iostream>
    #include <thread>
    #include <SDL2/SDL.h>
    #include <cstdlib>
    extern "C" {
    #include <readline/readline.h>
    }
    
    int main(int argc, char *argv[])
    {
        SDL_Init(SDL_INIT_VIDEO);
        auto window = SDL_CreateWindow("title", 0, 0, 200, 200, SDL_WINDOW_SHOWN);
    
        std::thread console([](){
            while (true) {
                char *console_input_c_str = readline("> ");
                if (console_input_c_str == NULL)
                    break;
                std::cout << "line: " << console_input_c_str << '\n';
                std::free(console_input_c_str);
            }
        });
    
        while (true) {
            SDL_Event event;
            SDL_WaitEvent(&event);
            std::cerr << "received event type "<<event.type<<'\n';
            if(event.type == SDL_WINDOWEVENT &&
                    event.window.event == SDL_WINDOWEVENT_CLOSE)
                break;
        }
    
        SDL_DestroyWindow(window);
        SDL_Quit();
        console.join();
    }
    

    主线程创建一个窗口 window 使用sdl2,输入sdl事件循环,而线程 console 使用从控制台重复读取 readline . 当窗口退出时,它等待控制台线程完成,然后退出。

    程序运行良好;但是, 如何使控制台线程在窗口退出时停止?

    如果程序只使用一个线程就可以了。如果退出控制台readline退出程序也可以。


    Exit readline is easy ,但所有答案都有问题- pthread_kill reset -Q 不可携带。

    Terminating a thread is easy (使用) std::terminate .detach() ,但控制台处于错误状态,因为 读出线 不要正常终止。要重置控制台,可以使用 复位-Q ,但那不是便携式的。

    使用readline的替代(异步)接口不起作用,因为sdl不监听控制台上的事件。使用 select 也不便于携带。

    1 回复  |  直到 6 年前
        1
  •  0
  •   user202729 Nati Keidar    6 年前

    事实上, readline 不是完全阻塞,它调用 rl_event_hook 每1/10秒(默认情况下)。可以检查程序是否在事件钩子内停止,如果是这样做的话 longjmp throw 退出函数(在本例中 int 使用,尽管可以定义自己的异常类):

    std::atomic<bool> stopped (false);
    
    rl_event_hook = [](){
        if (stopped)
            throw 0;
        return 0;
    };
    
    try {
        /* something calls readline() */
    } catch (int) {
        rl_cleanup_after_signal();
    }
    return 0;
    

    在主线程中使用:

    stopped = true;
    console.join();