1

マルチスレッドの理解を固めようとしています。私は自分自身を教えるために最善を尽くしていますが、これらの問題のいくつかは明確にする必要があります.

コードの一部を 3 回繰り返し、ロックを試してみました。

このコードで、ロックが必要なのは this.managerThreadPriority だけです。

まず、最小限のロックを使用した単純な手続き型アプローチです。

var managerThread = new Thread
(
    new ThreadStart(this.ManagerThreadEntryPoint)
);

lock (this.locker)
{
    managerThread.Priority = this.managerThreadPriority;
}

managerThread.Name = string.Format("Manager Thread ({0})", managerThread.GetHashCode());

managerThread.Start();

次に、新しいスレッドを作成して起動する単一のステートメントですが、ロックの範囲が大きすぎて、スレッドの作成と起動を含めることができません。コンパイラは、 this.managerThreadPriority が使用された後にロックを解放できることを魔法のように知りません。

この種の素朴なロックは避けるべきだと思います。

lock (this.locker)
{
    new Thread
    (
        new ThreadStart(this.ManagerThreadEntryPoint)
    )
    {
        Priority = this.managerThreadPriority,
        Name = string.Format("Manager Thread ({0})", GetHashCode())
    }
    .Start();
}

最後に、共有フィールドの周りにのみ「埋め込み」ロックを使用して、新しいスレッドを作成して起動する単一のステートメントです。

new Thread
(
    new ThreadStart(this.ManagerThreadEntryPoint)
)
{
    Priority = new Func<ThreadPriorty>(() =>
    {
        lock (this.locker)
        {
            return this.managerThreadPriority;
        }
    })(),

    Name = string.Format("Manager Thread ({0})", GetHashCode())
}
.Start();

lock ステートメントのスコープについてコメントしますか? たとえば、ifステートメントでフィールドを使用する必要があり、そのフィールドをロックする必要がある場合、ステートメント全体をロックしないようにする必要がありますifか? 例えば

bool isDumb;

lock (this.locker) isDumb = this.FieldAccessibleByMultipleThreads;

if (isDumb) ...

対。

lock (this.locker)
{
    if (this.FieldAccessibleByMultipleThreads) ...
}
4

3 に答える 3

3

lock ステートメントのスコープについてコメントしますか? たとえば、if ステートメントでフィールドを使用する必要があり、そのフィールドをロックする必要がある場合、if ステートメント全体をロックしないようにする必要がありますか?

一般に、リソースを保護する必要があるコードの部分にスコープを設定する必要があります。これは、他のスレッドができるだけ早くそれを利用できるようにするためです。

ただし、ロックしているリソースが一貫性を維持する必要がある全体像の一部であるかどうか、または他のリソースと直接関係のないスタンドアロンのリソースであるかどうかによって異なります

同期された方法ですべて変更する必要がある相互に関連するパーツがある場合、そのパーツのセット全体をプロセス全体にわたってロックする必要があります。他の何にも結合されていない独立した単一のアイテムがある場合、プロセスの一部がそれにアクセスするのに十分な時間だけ、その 1 つのアイテムをロックする必要があります。

別の言い方をすれば、リソースへの同期または非同期アクセスを保護していますか?

同期アクセスは、リソースが含まれる全体像に関心があるため、一般にそれをより長く保持する必要があります。関連リソースとの一貫性を維持する必要があります。このような場合、すべてが処理されるまで中断を回避したい場合は、for ループ全体をラップすることをお勧めします。

非同期アクセスは、できるだけ短時間保持する必要があります。したがって、ロックのより適切な場所は、for ループや if ステートメントの内部など、コードの一部の内部であるため、他の要素が処理される前であっても、個々の要素をすぐに解放できます。


これらの 2 つの考慮事項とは別に、もう 1 つ追加します。2 つの異なるロック オブジェクトを含むロックのネストは避けてください。特にコードの他の部分でデッドロックが使用されている場合は、これがデッドロックの原因になる可能性が高いことを経験から学びました。2 つのオブジェクトが、常に 1 つの全体として扱う必要があるグループの一部である場合は、そのようなネストをリファクタリングする必要があります。

于 2008-10-01T04:47:19.357 に答える
3

1) 他のスレッドを開始する前に、そのスレッドへの共有アクセスについてまったく心配する必要はありません。

2) はい、変更可能な共有データへのすべてのアクセスをロックする必要があります。(不変の場合、ロックは必要ありません。)

3) スレッド ID を示すために GetHashCode() を使用しないでください。Thread.ManagedThreadId を使用します。Thread.GetHashCode() を推奨する本があることは知っていますが、ドキュメントを見てください。

于 2008-09-30T21:43:23.933 に答える
0

スレッドを開始する前に何かをロックする必要はありません。

変数を読み取るだけの場合は、ロックも必要ありません。読み取りと書き込みを混在させる場合、ミューテックスと同様のロックを使用する必要があり、読み取りスレッドと書き込みスレッドの両方をロックする必要があります。

于 2008-09-30T21:54:50.707 に答える