和 或缓冲区刷新问题

Posted

技术标签:

【中文标题】\r 和 \n 或缓冲区刷新问题【英文标题】:Issues with \r and \n or Buffer Flushing 【发布时间】:2015-01-05 03:17:20 【问题描述】:

我在多个地方读到 \n 在使用时不会刷新缓冲区,但是在我的代码中,我将在这个问题的末尾添加,它似乎就是这样做的,或者至少看起来是这样的输出(由于我执行 couts 的方式,后台可能正在发生其他事情?)。

预期输出:

采矿激光 1 周期将在 x 秒内完成...

Mining Laser 2 周期将在 x 秒内完成...

Mining Laser 3 周期将在 x 秒内完成...

Mining Laser 4 周期将在 x 秒内完成...

我在 CLI 中获得的信息:

采矿激光 1 周期将在 x 秒内完成...

Mining Laser 2 周期将在 x 秒内完成...

Mining Laser 3 周期将在 x 秒内完成...

Mining Laser 4 周期将在 x 秒内完成...

采矿激光 1 周期将在 x 秒内完成...

Mining Laser 2 周期将在 x 秒内完成...

Mining Laser 3 周期将在 x 秒内完成...

Mining Laser 4 周期将在 x 秒内完成...

采矿激光 1 周期将在 x 秒内完成...

Mining Laser 2 周期将在 x 秒内完成...

Mining Laser 3 周期将在 x 秒内完成...

Mining Laser 4 周期将在 x 秒内完成...

我希望输出保持原样,就像预期的输出示例中的那样,并且在每次执行代码中的时间循环时更新自身。

这是我的代码:

#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>

using namespace std; //Tacky, but good enough fo a poc D:

class mLaser

public:
    mLaser(int clen, float mamt, int time_left)
    
        mlCLen = clen;
        mlMAmt = mamt;
        mCTime_left = time_left;
    

    int getCLen()
    
        return mlCLen;
    

    float getMAmt()
    
        return mlMAmt;
    

    void setMCOld(int old)
    
        mCTime_old = old;
    

    void mCycle()
    
        int mCTime_new = GetTickCount(); //Get current tick count for comparison to mCOld_time

        if (mCTime_old != ((mCTime_new + 500) / 1000)) //Do calculations to see if time has passed since mCTime_old was set
        
            //If it has then update mCTime_old and remove one second from mCTime_left.
            mCTime_old = ((mCTime_new + 500) / 1000);
            mCTime_left -= 1000;
        

        cur_time = mCTime_left; 
    

    int getCTime()
    
        return cur_time;
    

    int getCTLeft()
    
        return mCTime_left;
    


private:
    int mlCLen; //Time of a complete mining cycle
    float mlMAmt; //Amoung of ore produced by one mining cycle (not used yet)
    int cur_time; //The current time remaining in the current mining cycle; will be removing this as it is just a copy of mCTime_left that I was going to use for another possiblity to make this code work
    int mCTime_left; //The current time remaining in the current mining cycle
    int mCTime_old; //The last time that mCycle was called
;

void sMCycle(mLaser& ml, int i1, thread& _thread); //Start a mining cycle thread

//Some global defines
random_device rd;
mt19937 gen(rd());

uniform_int_distribution<> laser(1, 3); //A random range for the number of mlaser entities to use
uniform_int_distribution<> cLRand(30, 90); //A random time range in seconds of mining cycle lengths
uniform_real_distribution<float> mARand(34.0f, 154.3f); //A random float range of the amount of ore produced by one mining cycle (not used yet)

int main()

    //Init some variables for later use
    vector<mLaser> mlasers; //Vector to hold mlaser objects
    vector<thread> mthreads; //Vector to hold threads
    vector<shared_future<int>> futr; //Vector to hold shared_futures (not used yet, might not be used if I can get the code working like this)

    int lasers; //Number of lasers to create
    int cycle_time; //Mining cycle time
    int active_miners = 0; //Number of active mining cycle threads (one for each laser)
    float mining_amount; //Amount of ore produced by one mining cycle (not used yet)

    lasers = laser(gen); //Get a random number
    active_miners = lasers; //Set this to that random number for the while loop later on

    //Create the mlaser objects and push them into the mlasers vector
    for (int i = 0; i < lasers; i++)
    
        int clength = cLRand(gen);

        mlasers.push_back(mLaser(clength, mARand(gen), (clength * 1000)));
        
        //Also push thread obects into mthreads for each laser object
        mthreads.push_back(thread());
    

    //Setup data for mining cycles
    for (int i = 0; i < mlasers.size(); i++)
    
        int mCTime_start = GetTickCount(); //Get cycle start time
        mlasers.at(i).setMCOld(((mCTime_start + 500) / 1000));
    

    //Print initial display for mining cycles
    for (int i = 0; i < mlasers.size(); i++)
    
        cout << "Mining Laser " << i+1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds...\n";
    

    while (active_miners > 0)
       
        for (int i = 0; i < mlasers.size(); i++)
        
            //futr.push_back(async(launch::async, [mlasers, i, &mthreads]return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); ));
            async(launch::async, [&mlasers, i, &mthreads]return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); ); //Launch a thread for the current mlaser object
            //mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
        

        //Output information from loops
        cout << " \r" << flush; //Return cursor to start of line and flush the buffer for the next info

        for (int i = 0; i < mlasers.size(); i++)
        
            if ((mlasers.at(i).getCTLeft() != 0) //If mining cycle is not completed
            
                cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds...\n";
            

            else //If it is completed
            
                cout << "Mining Laser " << i + 1 << " has completed its mining cycle!\n";
                active_miners -= 1;
            
        
    

    
    /*for (int i = 0; i < mthreads.size(); i++)
    
        mthreads.at(i).join();
    */


    //string temp = futr.get();
    //float out = strtof(temp.c_str(),NULL);

    //cout << out << endl;

    system("Pause");
    return 0;


void sMCycle(mLaser& ml, int i1,thread& _thread)

    //Start thread
    _thread = thread(bind(&mLaser::mCycle, ref(ml)));
    
    //Join the thread
    _thread.join();

根据 Ben Voigt,似乎 \r 不能以我尝试使用它的方式使用。除了 Matthew 每次更新都关闭命令窗口的建议之外,还有其他人有什么建议吗?可能是 Boost 中的某些内容或 c++11 中的新内容?

谢谢。

【问题讨论】:

这与冲洗无关,与对\r的不切实际的期望有关。 (特别是,当'\r 被处理时,您刚刚移动到一个全新的行,所以回到该行的开头没有任何用处) @BenVoigt 啊,所以如果有一个 \n 或一个 endl,\r down 就不能正常工作;出现在 cout 内?当只有一条打印线时,我可以正常工作。不知道。那么我可能不得不接受马修的建议。我还将更改我的 Q 标题以提高准确性。谢谢。 您剩下的选项大多是非标准的。 Windows 具有控制台功能,例如SetConsoleCursorPosition,可用于移动到上一行。 Linux 和其他 Unix 变体可能支持用于光标移动的 ANSI 转义序列。通常你会使用诸如 ncurses 之类的库来为你管理它并为你提供一定程度的可移植性(我很确定 Windows 也有一个可用的 curses 库)。 @BenVoigt 刚刚在看 nCurses。我可能会在我的基于文本的游戏的更高版本中查看它,但我认为我会接受 Matthew 的建议,因为它在开发时间方面成本相当低。感谢您的建议。 【参考方案1】:

您可以尝试在每次执行后清除控制台 使用类似 system("cls"); 这是一个帖子的链接 [How can I clear console

【讨论】:

这可以是评论 如果可能的话,我想尽量避免关闭输出,因为我希望它看起来无缝,这样就不会那么刺耳(基于文本的游戏经常出现在这样的情况下) . c++11 或 Boost 中是否有任何东西能够实现我想要做的事情?如果找不到其他东西,我会求助于 clsing。

以上是关于 和 或缓冲区刷新问题的主要内容,如果未能解决你的问题,请参考以下文章

Meteor - 脚本在刷新/仅在某些路由上无法正确加载 Web 音频缓冲区

刷新缓存区方式和刷新内存到磁盘方式总结。

Perl 缓冲区刷新

Linux学习笔记

当磁盘上的文件发生更改时,如何让 Emacs 自动刷新所有缓冲区?

HLS 流 HTML5 视频 - 缓冲 X 时间后刷新