c++, cin, cout, threads和sync_with_stdio的输出损坏

Corrupted output with C++, cin, cout, threads and sync_with_stdio

本文关键字:with stdio 输出 损坏 sync cin cout threads c++      更新时间:2023-10-16

我正试图在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();
}

如果我使用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

那么,问题在哪里?难道c++不能使用快速的标准输入/输出来实现多线程吗?

我终于找到了罪魁祸首。如果你在网上搜索,很多网站推荐使用sync_with_stdio调用,但是他们不讨论线程。

其他网站讨论iostreams和线程,比如这个,但这并不能解释为什么当我在中只使用一个线程中的std::cin,以及在它自己的线程中也使用std::cout 时,我的输出会损坏。

问题是,在内部,std::cin输入线程调用std::cout来刷新它的缓冲区,但是由于流没有与互斥锁或类似的东西同步,输出被破坏了。如果缓冲区在做不同的事情,我为什么要同步它们呢?为什么std::cin会干扰std::cout?

在c++中,默认情况下,标准流cin、cerr和clog与cout绑定。这是什么意思?这意味着当您尝试从cin中读取时,首先它将强制flush到cout。有时这是一些有用的东西,你可以在这里读到。

但在我的情况下,这引起了一些严重的问题,所以,如何解开流?使用方法非常简单:

std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cerr.tie(nullptr);

或者如果你的编译器不支持c++ 11:

std::ios_base::sync_with_stdio(false);
std::cin.tie(static_cast<ostream*>(0));
std::cerr.tie(static_cast<ostream*>(0));

这改变了我的输出,现在是正确的:

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

并且由于它避免了每次使用std::cin时进行刷新,所以它也更快:-)