web-dev-qa-db-ja.com

複数のスレッド間でバッファを共有する

一時ファイルを読み書きするために多くのIO=を実行しているジョブプロセスがありました。
今、IO実行の量を減らしたい(必要))。

したがって、最初のスレッド内のテキストファイルからのデータでいっぱいになる一種の循環バッファーを作成したいと思います。

コンシューマー(読み取り)スレッドは、このバッファーからデータをフェッチします。

問題は、同じ1つのバッファーから読み取る必要がある複数のコンシューマーが存在する可能性があることです。

バッファーの実装では、既存のラッパーを使用しないことをお勧めします(単純な配列で、インデックスを "再生"するだけで十分です)。

また、読者ごとに個別のバッファを作成したくありません。そしてもちろん、デッドロックや不要なブロックを回避したい。

[〜#〜]更新[〜#〜]
現在、循環バッファー(配列と2つのインデックス)を使用しています

問題は、複数のコンシューマーがアクセスできるバッファーをどのように実装して、各コンシューマーが相互に依存して他のコンシューマーから読み取ることができるかです(1つの衣装担当者が他のものよりも速く読み取る可能性があります)。

重要な更新
最初のスレッドは、それが消費者であることを知りません(そして知らないはずです)。バッファにデータを書き込み、データが終了するとフラグを立てます。

3
kenny

ベアアレイを使用すると、必要以上の作業が必要になります。人々はあなたの生活を楽にするためにデータ構造を思いつくために多くの時間を費やしてきましたので、それらを使用してください。

Queue を実装しようとしているようです。これは、コレクションに追加したり、後で削除したりできるデータ構造です。これは先入れ先出しで行われます。 Javaには Thread-Safe Queue も組み込まれています。そのクラスのインスタンスを作成し、各スレッドにそれへの参照を与えるだけです。プロデューサはキューにアイテムを追加すると、コンシューマはキューからアイテムを削除するか、キューが空の場合は別のアクションを実行します。

自分ですべてを実装することに本当に心が決まっている場合は、配列へのすべてのアクセスを 同期 して、2つのスレッドが同時にバッファにアクセスできないようにする必要があります。

編集:

以前は、すべてのコンシューマーがすべてのデータを読み取ることを望んでいたことは明らかではありませんでした。キューの実装を拡張して、アイテムの数を追跡し(size()を一定の時間にする)、キューがいっぱいの場合に例外をスローすることができます。

飛び出る問題を解決するには少しトリッキーです。各コンシューマのインデックスを追跡する必要があります。マップでこれを行うことができます。次に、すべてのコンシューマーが移動して項目を渡すと、その項目をポップして、マップ内のすべてのインデックスを更新できます。コンシューマーがpop()を呼び出し、アイテムを保持する必要がある場合、peek()に再ルーティングできます。

3
unholysampler

Java側面を見る disruptor を見てください。これは、非ブロッキングの高性能なスレッド間メッセージングライブラリです。これは、「従来の」ロックベースとは対照的ですほとんどの人がJava/JVMプログラミングでまだ使用している並行性ユースケースで避けたいスタイル(共有する必要がないのに、なぜ共有状態を扱うのか)。

1
Martijn Verburg

私はあなたがC++で説明しているようなクラスを作成しましたが、Javaは作成していません。テンプレートと組み合わせたシングルトンパターンを使用したので、バッファーのタイプとサイズがわかっていれば、正しいインスタンスを取得できます。したがって、異なるタイプの異なるバッファを同時に持つことができます。 Javaで正確にこれを行うことができるかどうかはわかりません。しかし、これに関係なく、以下に私が言うことはまだ成り立ちます。

実装に関しては、いくつかのセマフォとミューテックスが必要になります。私は2つのセマフォを使用しました。1つはバッファ内のアイテム数をカウントするため、もう1つは残りのスペース量をカウントするためです。次に、これらの関数をput()およびget()メソッドで使用して、スペースが残っているか、何か取るかを判断できます。バッファへのアクセスを保護するミューテックスを取得し、オブジェクトをコピーして、インデックスポインタを変更できることを実行しました。

セマフォを使用すると、パタースレッドがバッファに何かを配置する前にゲッタースレッドがそれを取得するシナリオで、ミューテックスのデッドロックを回避できます。インデックスポインターを使用してnumItems()関数を実装できます。これらのポインターを使用して、getおよびputに使用する配列のインディーを計算できます。

0
fwgx

問題は、各衣装担当者が他の衣装担当者から相互に依存して読み取ることができる複数の衣装担当者がアクセスできるこのようなバッファーを実装する方法です(1人の衣装担当者が他の衣装担当者よりも速く読み取る可能性があります)。

これを安全に行うには、一度に1つのスレッドのみがバッファにアクセスできるようにする必要があります。これは複雑な問題になる可能性がありますが、Javaの 同期されたメソッド は物事を簡素化します。簡単に言うと、あるスレッドがオブジェクトの同期メソッドを実行している場合、そのメソッドが完了するまで、そのオブジェクトの他の同期メソッドはどのスレッドでも実行できません。

したがって、あなたの仕事は、同期された読み取りおよび書き込みメソッドを使用して、バッファーのクラスを作成することです。プログラムの早い段階でそのクラスをインスタンス化し、結果のオブジェクトをすべてのプロデューサーとコンシューマーと共有します。 Javaのメソッド同期により、一度に1つのスレッドのみがオブジェクトにアクセスすることが保証されます。

0
Caleb

unholysamplerが言うこと+すべてのコンシューマを知っている必要があります(これがないと、すべてのコンシューマが実際にいくつかのバイトを読み取るかどうかがわからないため)。彼によって読み取られない配列。

1)プロデューサー側:スローまたはブロック2)彼をコンシューマーとして削除し、独自のキューを開始します(ただし、成長できるものを使用します)3)彼をコンシューマーとして削除し、読みたいときに例外をスローします。

0
user470365