C++ 写入标准输入(在 Windows 中)

C++ write to stdin (in Windows)

我有一个多线程 Windows 控制台应用程序,其控制线程运行用户输入循环,如下所示:

char c;
do {
    cin >> c;
    // Alter activity based on c
} while(c != 'q')
// Tell other threads to close, .join(), and do cleanup

但是在某个时候我希望程序本身能够优雅地退出。最明显的方法是将 "q\n" 放到标准输入流中。有合理的方法吗?

或者回调强制退出主控制循环(在主线程上)以便程序进入后续清理方法的一个很好的替代方法?

(到目前为止我发现的最接近的是 this,它需要生成一个子进程,而且看起来充其量只是笨拙的矫枉过正。)

您可以使用另一个标志作为所有线程的循环中断条件。线程间通信的问题可以通过 C++11 附带的同步对象来解决,例如 atomics or mutex.

我最终使用了@Captain Obvlious 的建议,但即便如此也很棘手(感谢 Windows!):一旦控制信号被处理,它就会导致未经检查的各种问题 char 输入循环。但是,通过以下添加,任何线程都可以通过调用 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);

优雅地结束程序
bool exiting = false;
bool cleanedUp = false;
void Cleanup() {
    if(!cleanedUp) cleanedUp = true;
    else return;
    // Tell other threads to close, .join(), and do cleanup
}

// https://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
bool ConsoleControl(DWORD dwCtrlType) {
    exiting = true; // This will cause the stdin loop to break
    Cleanup();
    return false;
}

int main() {
    SetConsoleCtrlHandler((PHANDLER_ROUTINE) ConsoleControl, true);
    .
    .
    .
    // Main user control loop
    char c;
    do {
        cin >> c;
        if(exiting) break;
        if(c < 0) continue; // This must be a control character
        // Alter activity based on c
    } while(c != 'q')
    Cleanup();
    return 0;
}

这是一个老问题,但我偶然发现了它并最终解决了原来的问题。

我用了WriteConsoleInput function to simulate a user entering keystrokes to the console. This code sample is based off of This question.

HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD dwTmp;
INPUT_RECORD ir[2];

ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
ir[0].Event.KeyEvent.dwControlKeyState = 0;
ir[0].Event.KeyEvent.uChar.UnicodeChar = 'q';
ir[0].Event.KeyEvent.wRepeatCount = 1;
ir[0].Event.KeyEvent.wVirtualKeyCode = 'Q';
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey('Q', MAPVK_VK_TO_VSC);

ir[1].EventType = KEY_EVENT;
ir[1].Event.KeyEvent.bKeyDown = TRUE;
ir[1].Event.KeyEvent.dwControlKeyState = 0;
ir[1].Event.KeyEvent.uChar.UnicodeChar = VK_RETURN;
ir[1].Event.KeyEvent.wRepeatCount = 1;
ir[1].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
ir[1].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);

WriteConsoleInput(hStdin, ir, 2, &dwTmp);

在我的系统上 MAPVK_VK_TO_VSC 没有定义,所以我用 0 代替。

您应该在适当的地方添加错误检查。

希望对您有所帮助。