59

助けが必要な質問が 3 つあります。

  1. lockステートメントパラメータとして渡される正しいオブジェクト/参照は何ですか? 多くのサンプル コードを見てきましたが、渡されたオブジェクト/参照は、アクセス修飾子staticが公開されていない限り、現在のクラスまたはプログラム内の他のクラスに関連していない可能性があることに気付きました。例えば:

    private Object anyObj = new Object();
    lock(anyObj){.....}
    
    private static readonly object Locker = new object();
    lock(Locker){.....}
    

    それは私には意味がありません。

  2. lockMSDN で、ステートメントも使用するマルチスレッドに関するサンプル コードを見つけました。サンプルでは、​​2 つのtry/catchブロックがあり、そのMonitor.Wait()中にあります。ロジックを正しく理解していれば、プログラムが/ブロックにreaderFlag入ることをまったく禁止します。コードはここからの例 2 です: http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspxtrycatch

  3. Windows フォームがアクティブである限り、バックグラウンドで実行されるスレッドを実行するにはどうすればよいですか?

4

4 に答える 4

82

何をどのようにロックするかは、何をしているかによって異なります。

たとえば、コーヒー メーカーなど、何らかのデバイスで作業しているとします。次のようなクラスがあるとします。

public CoffeeMaker {
    private IntPtr _coffeeHandle;
    private Object _lock = new Object();
}

この場合、_coffeeHandle (実際の物理デバイスへのポインター/ハンドル) へのアクセスを保護しているため、これは非常に簡単です。

public int AvailableCups {
    get {
        lock (_lock) {
            return GetAvailableCups(_coffeeHandle); // P/Invoked
        }
    }
}

public void Dispense(int nCups)
{
    lock (_lock) {
        int nAvail = GetAvailableCups(_coffeeHandle);
        if (nAvail < nCups) throw new CoffeeException("not enough coffee.");
        Dispense(_coffeeHandle, nCups); // P/Invoked
    }
 }

そのため、マルチスレッド アプリを実行している場合、(おそらく) ディスペンス中に使用可能なカップ数を読み取りたくありません (ハードウェア エラーである可能性があります)。ハンドルへのアクセスを保護することで、それを保証できます。また、既に調剤しているのに調剤を求められることもありません。それは悪いことなので、それも保護されます。最後に、十分な量のコーヒーが利用可能で、それを確認するために公共の財産を使用していないことに気付いた場合を除き、私は分配しません。魔法の言葉はアトミックです。問題を発生させずに切り離すことはできません。

保護が必要なリソースのインスタンスが 1 つしかない場合は、静的オブジェクトをロックとして使用します。「シングルトンはありますか?」と考えてください。これは、静的ロックが必要になる場合のガイドラインになります。たとえば、CoffeeMaker にプライベート コンストラクターがあるとします。代わりに、コーヒー マシンを構築するファクトリ メソッドがあります。

static Object _factLock = new Object();

private CoffeeMaker(IntPtr handle) { _coffeeHandle = handle; }

public static CoffeeMaker GetCoffeeMaker()
{
    lock (_factLock) {
        IntPtr _handle = GetCoffeeMakerHandle(); // P/Invoked
        if (_handle == IntPtr.Zero) return null;
        return new CoffeeMaker(_handle);
    }
 }

この場合、CoffeeMaker はハンドルが処理されるようにIDisposable を実装する必要があるように感じます。

ただし、いくつかの問題があります。コーヒーが足りない場合は、もっと作る必要があるかもしれませんが、それには長い時間がかかります。コーヒーの調合には時間がかかるため、リソースの保護には細心の注意を払っています。ここで、このコーヒー メーカーに関するものはすべて独自のスレッドにすべきであり、コーヒーが飲み終わったときに発生するイベントが必要であると考えています。その後、複雑になり始め、知ることの重要性を理解しています。あなたがロックしているものと、いつコーヒーを作るのを妨げないようにします。

また、「デッドロック」、「アトミック」、「モニター」、「待機」、および「パルス」という言葉がすべてあなたにとってなじみのないものに聞こえる場合は、一般的なマルチプロセッシング/マルチスレッドについて読んで、公平な理髪店の問題を解決できるかどうかを確認する必要があります。問題または食事の哲学者の問題、どちらもリソース競合の典型的な例です。

于 2012-12-07T14:00:18.127 に答える
36

1)コードが不完全です。常に特定の(共有)リソースをロックします。はanyObject、その共有オブジェクトとのライフタイムで1対1の密接な対応が必要です。

例えば:

a)シンプルだが最も直接的なパターン:

List<MyClass> sharedList = ...;
...
lock (sharedList) { sharedList.Add(item); }

このパターンには欠点があります。他のコードsharedListが他の理由でロックオンした場合はどうなりますか?通常、実際的な問題ではありませんが、推奨されるパターンが(b)である理由は次のとおりです。

List<MyClass> sharedList = ...;
private object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }

または、共有オブジェクトが静的である場合(c):

static List<MyClass> sharedList = ...;
private static object listLock = new object();
...
lock (listLock) { sharedList.Add(item); }

2)スレッドreaderFlagはtrueまたはfalseに交互に設定されるため、try/catchブロックが入力されます。同期は、Monitor.Pulse()および.Wait()を使用して行われます。Wait()は、デッドロックがない間、ロックを生成することに注意してください。

于 2012-12-07T13:26:07.263 に答える
6

1: 使用するオブジェクトは、適用しようとしているロックの粒度によって定義/定義されています。is が「現在のインスタンスに対して呼び出しているもの」である場合、aprivate readonly object syncLock = new object()は合理的です。「インスタンスに関係なく任意のコード」(特に静的) の場合、private readonly static object syncLock = new object(). リスト、キューなど、保護しようとしている明らかな「もの」がある場合もあります。主な間違っ決定は次thisのとおりです。インスタンスの外に漏れました。typeof(...)stringlock

2:現在のスレッドからロックをMonitor.Wait 解放し、「パルス」またはタイムアウトのいずれかを待ちます。その時点でスレッドはウェイクアップし、キューに参加し元のロックに戻ります (「s」は再入可能であることに注意してください)。 . これは、2 つのスレッドが a を使用して、パルスと待機によって相互Monitorシグナルを送ることができることを意味します。

3: 無関係。しかし、基本的には「定期的にフラグをチェックし、パルスされたときに」

于 2012-12-07T13:28:34.713 に答える
3

MSDNのドキュメントによると:

lockキーワード ...に提供される引数は、ロックの範囲を定義するために使用されます。...厳密に言えば、提供されたオブジェクトは、複数のスレッド間で共有されているリソースを一意に識別するためにのみ使用されるため、任意のクラス インスタンスにすることができます。ただし、実際には、このオブジェクトは通常、スレッド同期が必要なリソースを表します。

私の場合、変更が必要な正確な静的オブジェクトを渡しました。

于 2015-08-25T16:53:00.760 に答える