11

可能な限り最速の方法で多くのパケットを処理するプログラムをC++で作成しようとしています。標準からのすべてのパケットは、可能な限り高速に読み取られ、プールから1つのスレッドに送信されて処理が行われ、パケットを標準出力に書き込む出力スレッドに処理される必要があります。

C ++で標準の入力と出力を使用している場合は、入力または出力の前にstd :: ios_base :: sync_with_stdio(false)関数を呼び出すことをお勧めします。一部の環境では、これにより大幅な高速化が実現しますが、呼び出し後の入出力に標準のC関数を使用することは避けてください。

まあ、これは単一のスレッドで完全に機能するようです。しかし、私が言ったように、私の意図は、入力用に1つのスレッド、出力用に1つのスレッド、および並列処理用に複数のスレッドを使用することです。出力にいくつかの問題があります。これは出力スレッドです(非常に単純化されています):

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();
}

「\n」の代わりにstd::endlを使用した場合、破損は少なくなりましたが、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

私はついに犯人を見つけました。インターネットを検索する場合、多くのサイトがsync_with_stdio呼び出しの使用を推奨していますが、スレッドについては説明していません。

他のサイトでは、このようなiostreamとスレッドについて説明していますが、 1つのスレッドで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 に答える