Выход из readline из потока C ++ 11 с SDL2 - PullRequest
0 голосов
/ 08 января 2019

Рассмотрим простую программу: (требуется -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 завершает работу программы.


Выйти из readline легко , но там есть проблема со всеми ответами - pthread_kill или reset -Q не является переносимым.

Завершение потока легко (с использованием std::terminate или .detach()), но консоль остается в плохом состоянии, потому что readline не завершается нормально. Для сброса консоли можно использовать reset -Q, но это не переносимо.

Использование альтернативного (асинхронного) интерфейса readline не работает, поскольку SDL не прослушивает события на консоли. Использование select также не переносимо.

1 Ответ

0 голосов
/ 10 января 2019

На самом деле, 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();
...