首页 文章

使用C,cin,cout,线程和sync_with_stdio损坏输出

提问于
浏览
10

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

1 回答

  • 22

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

    其他网站谈论iostreams和线程,比如this one,但这并不能解释为什么我在 only one thread 和std :: cout in its own thread too 中使用std :: cin时输出已损坏 .

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

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

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

    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时都进行刷新,所以它也更快:-)

相关问题