使用SDL2从C ++ 11线程轻松退出readline

时间:2019-01-08 06:37:11

标签: c++ c++11 sdl-2 readline

考虑一个简单的程序:(当使用带有pthread的g ++进行编译时,需要-std=c++11 -lpthread -lreadline -lSDL2

#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();
}

主线程使用SDL2创建一个窗口window,进入SDL事件循环,而线程console使用readline从控制台重复读取。退出窗口后,它将等待控制台线程完成然后退出。

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

如果程序仅使用一个线程,那就很好。如果退出控制台readline退出程序,也很好。


Exit readline is easy,但那里的所有答案都有问题-pthread_killreset -Q不可移植。

Terminating a thread is easy(使用std::terminate.detach()),但由于readline不能正常终止,因此控制台处于错误状态。要重置控制台,可以使用reset -Q,但这不是可移植的。

使用readline的替代(异步)接口不起作用,因为SDL不监听控制台上的事件。使用select也是不可移植的。

1 个答案:

答案 0 :(得分:0)

实际上,readline并未完全阻止,它每1/10秒(默认情况下)调用rl_event_hook。可以检查程序是否在事件挂钩中停止,如果是,则longjmpthrow退出该函数(在本示例中使用的是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();