6

複数のスレッドがDoWork()以下の方法を定期的に実行するとします。ある時点で、2つのスレッドがこのメソッドの実行をほぼ同時に開始し、2つのローカルタイムスタンプオブジェクトの一方が他方よりも1ティック大きいと仮定します。

ICollection collection = // ...

public void DoWork()
{
    DateTime timestamp = DateTime.Now;

    lock(collection.SyncRoot)
    {
        // critical section
    }
}

スレッドAがt1に等しいタイムスタンプによって特徴付けられ、スレッドBがt1 + 1ティックに等しいタイムスタンプt2によって特徴付けられる場合、スレッドAは最初にクリティカルセクションへのアクセスを必要とします。

.NETは、複数のスレッドによるクリティカルセクションへのアクセスをどのように管理しますか?アクセス要求をキューに入れて、時系列に並べますか?つまり、スレッドアクセス要求の順序に従ってクリティカルセクションへのアクセスが保証されていますか?

4

2 に答える 2

6

スレッドの実行順序と、どのスレッドが最初にクリティカル セクションを取得するかについての保証はまったくありません。

スレッドの優先度でも順序が保証されないことに注意してください。異なるコア/CPU が異なる優先度でスレッドをまったく同時に実行でき、どのスレッドも最初にクリティカル セクションに到達して取得できます。

注 2: スレッドは任意の時点で実行/待機するようにスケジュールすることもできるため、同じスレッド内の 2 つの異なる操作が隣り合っているという事実は、それらが間に遅延なく次々に実行されることを意味しません。あなたの場合、スレッドAはタイムスタンプを取得するとすぐに停止する可能性があり、後で実行するようにスケジュールされているスレッドBは後でタイムスタンプを簡単に取得できますが、最初に重要なセクションに到達します。

于 2012-09-05T17:24:37.107 に答える
4

あなたは、プログラマーを永遠にスレッドのトラブルに巻き込むような大げさな仮説を立てています。タイムスタンプを最初に取得するスレッドが、最初にロックに入るとは限りません。オッズのみが高く、100% ではありません。スレッドは、オペレーティング システムのスケジューラによって横取りされます。これは、Monitor.Enter() へのメソッド呼び出しの実行を開始したばかりのスレッドを含め、任意のスレッドを中断する可能性があります。スケジューリングの決定により、A が一時停止され、B が最初にロックを取得できるようになる可能性があります。

また、スケジューラーが注文をまとめる必要もありません。A を実行するコアは、そのデータ キャッシュに「コレクション」オブジェクト参照を持っていない可能性があり、B を実行するコアが先に競争できるようにメモリ バスを待機している間、コアを十分に長くストールさせます。「レース」という言葉は適切です。ここで間違った仮定を行うと、コードにスレッド競合バグが発生します。

ロックの背後にあるメカニズムは、「同時」が存在しないことを保証できる唯一のエンティティであるプロセッサによって実装されます。すべてのマルチコア CPU は、Compare-and-swapアトミック命令を実装しています。.NET で使用されているバージョンは、この回答で確認できます。

于 2012-09-05T18:17:45.977 に答える