Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多线程控制台I/O_C++_Multithreading_Console - Fatal编程技术网

C++ 多线程控制台I/O

C++ 多线程控制台I/O,c++,multithreading,console,C++,Multithreading,Console,我在多线程应用程序中使用控制台。现在,它只接受输出(printf等),到目前为止我没有任何问题。然而,我也希望能够支持控制台输入,这就是我的生活变得复杂的地方 预先警告一下,我对使用控制台输入和输出的更复杂的细微差别非常不熟悉。我在这方面的经验仅限于printf/cout、scanf/cin和使用SetConsoleTextAttribute()更改颜色(在windows上) 我希望我的程序尽可能保持交叉兼容,但我并不反对必须编写特定于平台的代码,只要我能为其他平台找到可行的替代方案 从概念上讲

我在多线程应用程序中使用控制台。现在,它只接受输出(printf等),到目前为止我没有任何问题。然而,我也希望能够支持控制台输入,这就是我的生活变得复杂的地方

预先警告一下,我对使用控制台输入和输出的更复杂的细微差别非常不熟悉。我在这方面的经验仅限于printf/cout、scanf/cin和使用
SetConsoleTextAttribute()
更改颜色(在windows上)

我希望我的程序尽可能保持交叉兼容,但我并不反对必须编写特定于平台的代码,只要我能为其他平台找到可行的替代方案

从概念上讲,我希望控制台在它自己的线程上运行,这样它就可以在等待cin时锁定,而不会冻结整个程序或其他线程。任何线程都可以向该线程发送控制台输出,该线程将以干净的方式输出(可能使用线程安全队列),控制台读取的任何输入都会将命令发送到相应的线程


我的第一个问题是,当我输入一些输入时,任何输出都会出现在我打字的中间。我想处理的解决方案是保留控制台的底线以供输入,并让输出转到最后一行,将输入行向下推。如何执行此操作?

要禁用回显字符,请检查以下内容:

也许再加上

你可能还发现这些东西很有用: ,

您真的不想在写入控制台其余部分时尝试保留部分控制台以供输入。至少,如果你只是在写滚动文本,就不会。这是可能的,但充满了错误和比它的价值更多的麻烦。有关这些问题的一些提示,请参阅

当然,仅仅使用conio.h是不可能做到这一点的

您可以分配两个控制台屏幕缓冲区,一个用于输入,一个用于程序输出。当您的程序正常运行时,将选择输出屏幕缓冲区,您将看到输出在屏幕上滚动。但是,当程序等待用户输入时,您交换屏幕缓冲区,以便输出仍在进行,但在另一个屏幕缓冲区中

最后,您必须自己格式化输出并调用,将要写入的屏幕缓冲区句柄传递给它。事情变得非常复杂,很难正确处理。如果可能的话。我知道我过去花了太多时间在这上面,而且总是有一些奇怪的问题


我不会说你想做的是不可能的。然而,我要说的是,你将面临一段艰难的时期。

嗯,我用pdcurses解决了这个问题。如果其他人想做类似的事情,我是这样做的。首先,我初始化控制台如下:

Console::Console(bool makeConsole)
{
    if (makeConsole == false)
        return;

    if (self)
        throw ("You only need one console - do not make another!\n");
    self = this;

#ifdef WIN32
    AllocConsole();
#endif
    initscr();

    inputLine = newwin(1, COLS, LINES - 1, 0);
    outputLines = newwin(LINES - 1, COLS, 0, 0);

    if (has_colors())
    {
        start_color();
        for (int i = 1; i <= COLOR_WHITE; ++i)
        {
            init_pair(i, i, COLOR_BLACK);
        }
    }
    else
        wprintw(outputLines, "Terminal cannot print colors.\n");

    scrollok(outputLines, TRUE);
    scrollok(inputLine, TRUE);

    leaveok(inputLine, TRUE);
    nodelay(inputLine, TRUE);
    cbreak();
    noecho();
    keypad(inputLine, TRUE);

    initCommands();

    hello("Starting %s.\n", APP_NAME);
    hellomore("Version %i.%i.%i.\n\n", APP_MAJORVER, APP_MINORVER, APP_REVISION);
}
最后,输入。这一次需要相当多的微调

void Console::inputLoop(void)
{
    static string input;

    wattron(inputLine, A_BOLD | COLOR_PAIR(COLOR_WHITE));
    wprintw(inputLine, "\n> ");
    wattroff(inputLine, A_BOLD | COLOR_PAIR(COLOR_WHITE));

    wprintw(inputLine, input.c_str());
    wrefresh(inputLine);

    char c = wgetch(inputLine);
    if (c == ERR)
        return;

    switch (c)
    {
    case '\n':
        if (input.size() > 0)
        {
            sendFormattedMsg(COLOR_WHITE, "> ", COLOR_WHITE, input.c_str());
            cprint("\n");

            executeCommand(&input[0]);
            input.clear();
        }
        break;

    case 8:
    case 127:
        if (input.size() > 0) input.pop_back();
        break;

    default:
        input += c;
        break;
    }
}

这是从处理窗口消息的同一线程的每一帧运行的。我使用
nodelay()
禁用了
wgetch()
的阻塞行为,消除了在自己的线程中运行控制台输入的需要。我还禁用回显并手动回显输入。在输入窗口上启用滚动允许我使用简单的“\n”清除其内容,如果用户键入了任何内容,则用更新的内容替换它。它支持人们所期望的一切,从一个简单的、多线程的终端,到输入和接收多线程的输出。

我已经在使用conio.h(按任意键继续非常方便)。我确实希望输入输入的字符可以被回响,我不希望输出消息发生在中间。检查第一个链接,它显示如何禁用被按下的字符。这个想法是多个线程正在写入控制台输出,而另一个线程正在等待输入。我只是想避免冲突。问题是,“当您的程序正常运行时”和“当您的程序等待用户输入时”总是同时发生。现在我正在研究pdcurses.@HaydnV.Harach:您可以让输出线程始终向控制台写入数据。然后,您可以在用户按键时交换输出缓冲区,并将输出挂起(隐藏,实际上),直到用户完成输入,或者直到某个超时过期(因此,如果用户不按Enter键离开,输出将恢复)。这也许是一个不完美的解决方案,但它可以起作用。我可以通过额外的工作来妥善完成它。现在我正在使用pdcurses,但我遇到了几个障碍,即如何让文本滚动(现在它一直写到窗口底部,然后放弃),以及如何让两个“窗口”同时出现在屏幕上,每个窗口都接收输出(一个用于实际输出消息,一个用于回显输入)?人们习惯于留下评论来解释答案的错误。
void Console::inputLoop(void)
{
    static string input;

    wattron(inputLine, A_BOLD | COLOR_PAIR(COLOR_WHITE));
    wprintw(inputLine, "\n> ");
    wattroff(inputLine, A_BOLD | COLOR_PAIR(COLOR_WHITE));

    wprintw(inputLine, input.c_str());
    wrefresh(inputLine);

    char c = wgetch(inputLine);
    if (c == ERR)
        return;

    switch (c)
    {
    case '\n':
        if (input.size() > 0)
        {
            sendFormattedMsg(COLOR_WHITE, "> ", COLOR_WHITE, input.c_str());
            cprint("\n");

            executeCommand(&input[0]);
            input.clear();
        }
        break;

    case 8:
    case 127:
        if (input.size() > 0) input.pop_back();
        break;

    default:
        input += c;
        break;
    }
}