使用C++,cin,cout,threads和sync_with_stdio损坏输出

imr*_*era 11 c++ multithreading input corruption output

我试图用C++编写一个程序,以尽可能最快的方式处理大量数据包.来自标准的所有数据包应尽可能快地读取,从池中发送到一个线程进行处理,然后处理到将数据包写入标准输出的输出线程.

当您在C++中使用标准输入和输出时,建议在任何输入或输出之前调用std :: ios_base :: sync_with_stdio(false)函数.在某些环境中,这可以实现很大的加速,但是在调用之后应该避免使用标准C函数进行输入/输出.

嗯,这似乎在单个线程中完美运行.但正如我所说,我的意图是使用一个线程进行输入,一个用于输出,多个线程用于并行处理.我观察到输出有些问题.这是输出线程(非常简化):

void PacketDispatcher::thread_process_output(OutputQueue& output_queue) {
    std::vector<Packet> packet_list;
    while(output_queue.get(packet_list)) {
        for (const auto& packet: packet_list) {
            std::cout << "Packet id = " << packet.id << "\n";
        }
    }
    std::cout.flush();
}
Run Code Online (Sandbox Code Playgroud)

如果我使用std :: endl而不是"\n",那么腐败就会减少,但是std :: endl强制刷新流,在这种情况下影响性能(并且问题没有解决,只是最小化).

这是使用std :: cout的程序中唯一的一点,但是如果我在程序开始时调用std :: ios_base :: sync_with_stdio(false),我会得到一个明显的加速,但是我的输出总是被损坏了一些办法:

Packet id = Packet id = 4
Packet id = 5
Packet id = 6
Packet id = 7
Packet id = 8
Packet id = 9
Packet id = 10
Run Code Online (Sandbox Code Playgroud)

那么,问题出在哪里?C++不能使用快速标准输入/输出进行多线程处理吗?

imr*_*era 24

我终于找到了罪魁祸首.如果您搜索Internet,很多网站建议使用sync_with_stdio调用,但他们不会谈论线程.

其他网站谈论iostreams和线程,就像这个,但这并不能解释为什么当我在一个线程中使用std :: cin时,我的输出被损坏,而std :: cout 也在它自己的线程中.

问题是在内部,std :: cin输入线程正在调用std :: cout来刷新其缓冲区,但由于流与未与mutex或类似的东西同步,输出已损坏.如果他们正在做不同的事情,我为什么要同步缓冲区呢?为什么std :: cin搞乱了std :: cout?

在C++中,默认情况下,标准流cin,cerr和clog与cout绑定.这是什么意思?这意味着当你尝试从cin读取时,首先它会强制刷新cout.有时这是有用的,你可以在这里阅读.

但在我的情况下,这导致了一些严重的问题,那么,如何解开溪流呢?使用tie方法非常简单:

std::ios_base::sync_with_stdio(false);

std::cin.tie(nullptr);
std::cerr.tie(nullptr);
Run Code Online (Sandbox Code Playgroud)

或者如果您的编译器不支持C++ 11:

std::ios_base::sync_with_stdio(false);

std::cin.tie(static_cast<ostream*>(0));
std::cerr.tie(static_cast<ostream*>(0));
Run Code Online (Sandbox Code Playgroud)

随着这个改变我的输出现在是正确的:

Packet id = 1
Packet id = 2
Packet id = 3
Packet id = 4
Packet id = 5
Packet id = 6
Packet id = 7
Packet id = 8
Packet id = 9
Packet id = 10
Run Code Online (Sandbox Code Playgroud)

因为它避免每次使用std :: cin时都进行刷新,所以它也更快:-)

  • 接得好.所以stdout的存在是因为很多人都这样做:`cout <<"你叫什么名字?"; cin >> name;`,当没有输出时会被混淆.一些C库没有"读取前刷新",这导致至少初学者感到困惑. (2认同)