考虑一个简单的程序:(当使用带有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_kill
或reset -Q
不可移植。
Terminating a thread is easy(使用std::terminate
或.detach()
),但由于readline
不能正常终止,因此控制台处于错误状态。要重置控制台,可以使用reset -Q
,但这不是可移植的。
使用readline的替代(异步)接口不起作用,因为SDL不监听控制台上的事件。使用select
也是不可移植的。
答案 0 :(得分:0)
实际上,readline
并未完全阻止,它每1/10秒(默认情况下)调用rl_event_hook
。可以检查程序是否在事件挂钩中停止,如果是,则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();