TLDR; 主な質問のバージョン:
スレッドを操作している間、リストの内容を削除せず (順序を再編成)、新しいオブジェクトが完全に追加された後にのみ新しいオブジェクトを読み取る限り、1 つのスレッドでリストの内容を読み取り、別のスレッドでリストの内容を読み取ることは安全ですか?
Int が 1 つのスレッドによって「古い値」から「新しい値」に更新されている間に、別のスレッドがこの Int を読み取ると、返される値が「古い値」でも「新しい値」でもないリスクがありますか?
スレッドが重要な領域を「スキップ」することは可能ですか?
別のスレッドで実行されている 2 つのコードがあり、一方を他方のプロデューサーとして機能させたいと考えています。アクセスを待機している間、どちらのスレッドも「スリープ」したくありませんが、他のスレッドがこれにアクセスしている場合は、代わりに内部コードをスキップします。
私の当初の計画は、このアプローチを介してデータを共有することでした (そして、カウンターが十分に高くなったら、オーバーフローを避けるためにセカンダリ リストに切り替えます)。
私が最初に意図したフローの疑似コード。
Producer
{
Int counterProducer;
bufferedObject newlyProducedObject;
List <buffered_Object> objectsProducer;
while(true)
{
<Do stuff until a new product is created and added to newlyProducedObject>;
objectsProducer.add(newlyProducedObject_Object);
counterProducer++
}
}
Consumer
{
Int counterConsumer;
Producer objectProducer; (contains reference to Producer class)
List <buffered_Object> personalQueue
while(true)
<Do useful work, such as working on personal queue, and polish nails if no personal queue>
//get all outstanding requests and move to personal queue
while (counterConsumer < objectProducer.GetcounterProducer())
{
personalQueue.add(objectProducer.GetItem(counterconsumer+1));
counterConsumer++;
}
}
これを見ると、一見問題ないように見えましたが、キューから半分構築された製品を取得することはないことがわかっていたので、リストがどこにあるかに関係なく、途中でスレッドの切り替えが発生したとしても、リストのステータスは問題にならないはずです。プロデューサーは新しいオブジェクトを追加しています。この仮定は正しいですか、それともここに問題がある可能性がありますか? (私の推測では、消費者がリスト内の特定の場所を要求し、新しいオブジェクトが最後に追加され、オブジェクトが削除されることはなく、これが問題にならないためです)
しかし、私の目を引いたのは、「counterProducer++」である間に「counterProducer」が不明な値であるという同様の問題が発生する可能性があることでした。これにより、一時的な値が「null」または不明な値になる可能性がありますか? これは潜在的な問題になりますか?
私の目標は、ミューテックスを待っている間、2 つのスレッドのどちらもロックせずにループを続行することです。これが、ロックがないため、最初に上記を作成した理由です。
リストの使用が問題を引き起こす場合、私の回避策は、リンクされたリストの実装を作成し、2 つのクラス間で共有し、カウンターを使用して新しい作業が追加されたかどうかを確認し、personalQueue が新しく移動する間、最後の場所を保持することです。パーソナル キューに追加します。したがって、プロデューサーは新しいリンクを追加し、コンシューマーはそれらを読み取り、以前のリンクを削除します。(リストにカウンターはなく、追加および削除された量を知るための外部カウンターのみ)
counterConsumer++ リスクを回避するための代替疑似コード (これについては助けが必要です)。
Producer
{
Int publicCounterProducer;
Int privateCounterProducer;
bufferedObject newlyProducedObject;
List <buffered_Object> objectsProducer;
while(true)
{
<Do stuff until a new product is created and added to newlyProducedObject>;
objectsProducer.add(newlyProducedObject_Object);
privateCounterProducer++
<Need Help: Some code that updates the publicCounterProducer to the privateCounterProducer if that variable is not
locked, else skips ahead, and the counter will get updated at next pass, at some point the consumer must be done reading stuff, and
new stuff is prepared already>
}
}
Consumer
{
Int counterConsumer;
Producer objectProducer; (contains reference to Producer class)
List <buffered_Object> personalQueue
while(true)
<Do useful work, such as working on personal queue, and polish nails if no personal queue>
//get all outstanding requests and move to personal queue
<Need Help: tries to read the publicProducerCounter and set readProducerCounter to this, else skips this code>
while (counterConsumer < readProducerCounter)
{
personalQueue.add(objectProducer.GetItem(counterconsumer+1));
counterConsumer++;
}
}
したがって、コードの 2 番目の部分の目標であり、これをコーディングする方法を理解できませんでしたが、もう一方が publicCounterProducer を更新する「重要な領域」にある場合に、両方のクラスが他方を待たないようにすることです。ロック機能を正しく読み取ると、スレッドは解放を待ってスリープ状態になりますが、これは私が望んでいるものではありません。ただし、それを使用しなければならなくなる可能性があります。その場合、最初の疑似コードでそれを行い、値の取得時に「ロック」を設定するだけです。
私の多くの質問で私を助けてくれることを願っています。