11

我正在尝试用 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++ 不能使用快速标准输入/输出进行多线程吗?

4

1 回答 1

26

我终于找到了罪魁祸首。如果您在 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);

或者,如果您的编译器不支持 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 时都进行刷新,所以它也更快:-)

于 2012-12-23T10:12:30.127 回答