C ++,cin,cout,线程和sync_with_stdio的输出损坏 [英] Corrupted output with C++, cin, cout, threads and sync_with_stdio

查看:145
本文介绍了C ++,cin,cout,线程和sync_with_stdio的输出损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to make a program in C++ to process a lot of packets in the fastest way possible. All the packets come from the standard should be read as fast as possible, sent to one thread from a pool to do the processing and then handled to an output thread that will write the packet to the standard output.

在C ++中使用标准输入和输出时,建议在任何输入或输出之前调用

When you are using the standard input and output in C++, it's recommended that before any input or output you call to the std::ios_base::sync_with_stdio(false) function. In some environments this achieves a great speedup, although you should avoid using standard C functions for input/output after the call.

好吧,这似乎可以在单个线程中完美地工作.但是正如我已经说过的那样,我的意图是使用一个线程作为输入,一个线程用于输出,而多个线程用于并行处理.我已经观察到输出中的一些问题.这是输出线程(非常简化):

Well, this seems to work perfectly in a single thread. But as I have said my intention is using one thread for input, one for output and multiple threads for parallel processing. I've observed some problems with the output. This is the output thread (very simplified):

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会强制刷新流,从而影响性能这种情况(问题没有得到解决,只有最小化了).

If I used std::endl instead of "\n" there were less corruption, but std::endl forces a flush of the stream, affecting performance in this case (and the problem wasn't solved, only minimized).

这是使用std :: cout的程序中的唯一要点,但是如果我调用 std :: ios_base :: sync_with_stdio(false)在程序开始时,我得到了明显的加速,但是我的输出总是以某种方式损坏:

That's the only point in the program using std::cout, but if I make the call to std::ios_base::sync_with_stdio(false) at the beggining of the program I get a noticeable speedup, but my output is corrupted always in some way:

Packet id = Packet id = 4
Packet id = 5
Packet id = 6
Packet id = 7
Packet id = 8
Packet id = 9
Packet id = 10

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

So, where is the problem? Isn't C++ able to do multithreading using fast standard input/output?

推荐答案

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

I finally found the culprit. If you search for Internet a lot of sites recommends using the sync_with_stdio call, but they don't talk about threads.

其他站点谈论iostream和线程,例如这一个,但事实并非如此.不会解释为什么我在仅一个线程中使用std :: cin而在自己的线程中也使用std :: cout 时却得到了损坏的输出.

Other sites talk about iostreams and threads, like this one, but that doesn't explain why I was getting corrupted output when I was using std::cin in only one thread, and std::cout in its own thread too.

问题是内部,std :: cin输入线程正在调用std :: cout刷新其缓冲区,但是由于流未与互斥锁或类似对象同步,因此输出已损坏.如果缓冲区执行不同的操作,为什么还要同步它们?为什么std :: cin与std :: cout搞混了?

The problem is that internally, the std::cin input thread was calling to std::cout to flush its buffer, but as the streams where not synchronized with mutex or something similar, the output was corrupted. Why should I synchronized the buffers if they are doing different things? Why std::cin was messing with std::cout?

在C ++中,默认情况下,标准流cin,cerr和clog与cout绑定在一起.这是什么意思?这意味着,当您尝试从cin读取内容时,它将首先强制将冲洗清除为cout.有时候这很有用,因为您可以在此处阅读.

In C++, by default, the standard streams cin, cerr and clog are tied to cout. What does this mean? It means that when you try to read from cin, first it will force a flush to cout. Sometimes this is something useful as you can read here.

但是就我而言,这引起了一些严重的问题,因此,如何解开流?使用 tie方法 非常容易:

But in my case, this was causing some serious issues, so, how to untie the streams?. It's very easy using the tie method:

std::ios_base::sync_with_stdio(false);

std::cin.tie(nullptr);
std::cerr.tie(nullptr);

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

Or if your compiler doesn't support C++11:

std::ios_base::sync_with_stdio(false);

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

通过此更改,我的输出现在是正确的:

With this changes my output it's now correct:

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

And as it avoids doing a flush every time std::cin is used, it's faster too :-)

这篇关于C ++,cin,cout,线程和sync_with_stdio的输出损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆