web-dev-qa-db-ja.com

C#ロックステートメント、ロックするオブジェクト

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

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

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

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

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

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

52
user1885498

どのように、何をロックするかは、あなたが何をしているかに依存します。

ある種のデバイスで作業しているとしましょう-コーヒーメーカーなどです。次のようなクラスがあります。

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
    }
 }

したがって、マルチスレッドアプリケーションを実行している場合、(おそらく)ディスペンシング中に使用可能なカップの数を読みたくありません(ハードウェアエラーの可能性があります)。ハンドルへのアクセスを保護することで、それを保証できます。また、すでに調剤している間は調剤を依頼することはできません。それは悪いことなので、それも保護されています。最後に、十分なコーヒーが手元にない限り、私は調剤しません-そして、あなたは私がdo n'tに気づいたことに気づきました-このようにして、十分なコーヒーと調剤を確保するという行為が結びついています。魔法の言葉はアトミックです-問題を作成せずにそれらを切り離すことはできません。

保護が必要なリソースのインスタンスが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は implement IDisposable のように感じるので、ハンドルを引き継ぐことができます。リリースしないと、誰かがコーヒーを飲まない可能性があるためです。

しかし、いくつかの問題があります-たぶん、十分なコーヒーがなければ、もっと作る必要があります-それには長い時間がかかります。ヘック-コーヒーの供給には時間がかかるため、リソースを保護するように注意しています。今、あなたは本当にこのすべてのコーヒーメーカーのものがそれ自体のスレッドにあるべきであり、コーヒーが完了すると発生するイベントがあり、それが複雑になり始め、あなたが知ることの重要性を理解する必要があると考えていますあなたがロックしているものと、コーヒーを作るのをブロックしないように、あなたはそこにカップがいくつあるかを尋ねたので。

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

74
plinth

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()は、デッドロックがない期間sの間ロックを生成することに注意してください。

33
Henk Holterman

1:使用するオブジェクトは、強制しようとしているロックの粒度を定義/定義します。 isが「現在のインスタンスに対して呼び出すもの」であれば、private readonly object syncLock = new object()が妥当です。 「インスタンスに関係なく、任意のコード」(特に静的)の場合、private readonly static object syncLock = new object()。保護しようとしている明らかな「もの」が存在する場合があります。それはリスト、キューなどです。主な間違ったの決定は:thistypeof(...)、任意のstring、各lockに対してボクシングしている任意の値型、およびインスタンスの外部にリークしたもの。

2:Monitor.Waitreleases現在のスレッドからのロック。「パルス」またはタイムアウトのいずれかを待機し、その時点でウェイクアップしてキューをregain持っていたロックに(再入可能性のために「s」があることに注意してください)。つまり、2つのスレッドは、パルシングと待機により、Monitor tosignalを使用できます。

3:無関係。しかし、基本的には「定期的にフラグをチェックし、パルスが発生するとき」

6
Marc Gravell

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

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

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

2
Vladimir T.