2016-08-27 16 views
1

ロックフリーキューを使用してマルチスレッドセーフのロガーを作成したいと思います。ロギングスレッドはメッセージをキューにプッシュし、ロガーはメッセージをポップして出力に送信します。私はその問題を解決する方法を考えています。 可能であれば、mutex/locksの使用を避けたいと思います。 ファイル/コンソールに書き込むためにC++ストリームを使用すると仮定しましょう。ターゲットシステムはLinuxと仮定できます。アトミックシステムコール。入力/出力操作

いいえ、ストリームへの書き込みは、Unix writeによって提供されるシステムコール用の単なるラッパー(おそらく高度なラッパー)でなければなりません。私が知っていることから、syscallsはアトミックです(1つのプロセスだけが同時にシステムコールを実行できます)。したがって、ファイルへの安全な書き込みを行うためにロックを使用しないことが魅力的です。 しかし、writeはシステムコールですが、 "出力全体"を書くことは保証しません。これは、ファイルに正常に書き込まれたバイト数を返します。

基本的に私の質問は: どのように解決するのですか?ミューテックスを避けることは可能ですか? (私はそれが不可能だと思う)。そして、私の考えをマークしてください、間違っていますか?

+0

私はかなりの性質を理解しているのか分かりません問題。あなたはあなたが誰と競合していると信じていますか? 「相互の」排除は、リソースを共有しようとする少なくとも2つの当事者の存在を前提としています。 –

+0

ストリームに競合する2つのスレッドがあります。 – Gilgamesz

+0

さて、このような複雑な設定では、実際にI/Oを実行するスレッドが1つしかないという明白な目的のためにキューを用意しています。なぜ、あなたは同じファイルに多くのスレッドを書くことで独自のデザインを妨害しますか?そのキューを持っているのは何ですか?あなたが先に進み、ファイルにフリー・フォー・オール・ア・オール・フォー・オールを書いたら? –

答えて

2

イゴールが正しいです:ただ1つのスレッドですべてのログ書き込みを実行してください。カーネルは、ファイルの位置を把握しているオープンファイルディスクリプタへのアクセスを同期させるためにロックを行う必要があるので、複数のコアからの書き込みを行うことで、カーネル内部の競合を引き起こしていることに注意してください。さらに悪いことに、複数のコアからシステムコールを行っているため、カーネルのコード/データアクセスによって複数のコア上のキャッシュが汚れることになります。

システムコールがsyscallの完了後にユーザ空間コードのパフォーマンスに与える影響の詳細については、this paperを参照してください。 (まれにあるシステムコールのために、カーネル内部のデータ/命令キャッシュミスについて)。 1つのスレッドがすべてのシステムコールを実行するようにすることは間違いありません。少なくとも、すべてのシステムコールを書き込んで、プロセスのフットプリントの一部を1つのコアに分離してください。カーネル内部のロック競合と同様に。

FlexSCの論文では、ユーザ - >カーネル - >ユーザの遷移を減らすためのシステムコールのバッチ処理について考えていますが、通常の同期システムコールメソッドのオーバーヘッドも測定します。さらに重要なことは、システムコールからのキャッシュ汚染の議論です。


また、ログファイルに複数のスレッドを書き込ませることができれば、それを実行してキューをまったく使用しなくてもかまいません。

大量の書き込みが途切れなくなることは保証されていませんが、中小サイズの書き込みではほとんどのOSで常にバッファ全体をコピーする必要があります。特に、パイプではなくファイルに書き込んでいる場合。 Linux write()はプリエンプション時にどのように動作するのかをIDKが知っていますが、通常は、要求されたバイトをすべて書き込むことなく、書き戻すのではなく書き込みを終了することを期待しています。部分的な書き込みは、信号によって中断された場合に起こりやすくなります。

2つのwrite()システムコールのバイトが混在しないことが保証されています。一方からのすべてのバイトは、他方からのバイトの前後になります。あなたは部分的な書き込みが潜在的な問題であるということは間違いありません。 glibcのシステムコールラッパーがEINTRの呼び出しを再開するかどうか忘れてしまいます。その場合は、実際に書き込まれたバイトがないことを意味しますが、バイト数で成功を返していたはずです。

部分的な書き込みとパフォーマンスのためにこれをテストする必要があります。カーネルスペースのロックはロックフリーのキューのオーバーヘッドよりも安いかもしれませんが、ログメッセージを生成するすべてのスレッドからシステムコールを実行すると、パフォーマンスが低下する可能性があります。(そして、あなたがこれをテストするときに、だけがの呼び出しを書くだけでなく、あなたのユーザスペースプロセスで起こっている実際の仕事でそれを行うことを確かめてください)

+0

ありがとう:) "これをテストするときには、書き込みを呼び出すループだけでなく、ユーザー空間プロセスで実際の作業が行われていることを確認してください。" ええ、私はそれを満たしています:) - ロック - 競合: – Gilgamesz

関連する問題