5

C ++の一般的なパターンは、ロックをラップするクラスを作成することです。ロックは、オブジェクトの作成時に暗黙的に取得されるか、後で明示的に取得されます。オブジェクトがスコープ外になると、dtorは自動的にロックを解除します。C#でこれを行うことは可能ですか?私が理解している限り、オブジェクトがスコープ外になった後、C#のdtorがいつ実行されるかについての保証はありません。

明確化:一般的なロック、スピンロック、ReaderWriterLockなど。Disposeを呼び出すと、パターンの目的が無効になります。つまり、スコープを終了するとすぐにロックが解放されます。途中でreturnを呼び出したり、例外をスローしたりするかどうかは関係ありません。また、私が理解している限り、使用するとGCのオブジェクトのみがキューに入れられ、すぐに破棄されることはありません...

4

6 に答える 6

12

ティモシーの答えを増幅するために、lock ステートメントはモニターを使用してスコープ付きロックを作成します。基本的に、これは次のように変換されます。

lock(_lockKey)
{
    // Code under lock
}

// is equivalent to this
Monitor.Enter(_lockKey)
try
{
     // Code under lock
}
finally
{
    Monitor.Exit(_lockKey)
}

C# では、この種のパターンに dtor を使用することはめったにありません (using ステートメント/IDisposable を参照してください)。コードで気付くことの 1 つは、Monitor.Enter と try の間で非同期例外が発生した場合、モニターが解放されないように見えることです。JIT は実際に、Monitor.Enter が try ブロックの直前にある場合、try ブロックまで非同期例外が発生しないという特別な保証を行い、解放を保証します。

于 2008-11-02T12:23:58.787 に答える
5

に関するあなたの理解usingは正しくありません。これは、スコープ付きアクションを決定論的な方法で発生させる方法です (GC へのキューイングは行われません)。

C#lockは、排他ロックを提供するキーワードを提供します。異なるタイプ (読み取り/書き込みなど) が必要な場合は、usingステートメントを使用する必要があります。

PSこのスレッドはあなたに興味があるかもしれません.

于 2008-11-02T12:25:19.563 に答える
4

dtor がいつ実行されるか正確にわからないのは事実ですが、IDisposable インターフェイスを実装し、「using」ブロックを使用するか、「Dispose()」を自分で呼び出すと、コードを置く場所。

質問: 「ロック」とは、一度に 1 つのスレッドだけがオブジェクトを使用できるようにするためのスレッド ロックを意味しますか? 次のように:

lock (_myLockKey) { ... }

どうか明らかにしてください。

于 2008-11-02T12:03:37.190 に答える
3

完全を期すために、 と を使用せずに同様の RAII 効果を実現する別の方法がusingありIDisposableます。通常、 C#のusing方が明確ですが (詳細についてはこちらも参照してください)、他の言語 (Java など) や C# でさえusing何らかの理由で適切でない場合は、知っておくと役立ちます。

これは「Execute Around」と呼ばれるイディオムであり、アイデアは、事前および事後処理 (スレッドのロック/ロック解除、DB 接続のセットアップとコミット/クローズなど) を行うメソッドを呼び出し、それに渡すことです。間に発生させたい操作を実装するデリゲートをメソッド化します。

例えば:


funkyObj.InOut( delegate{ System.Console.WriteLine( "middle bit" ); } );

InOut メソッドの動作に応じて、出力は次のようになります。

最初のビット
中ビット
最後のビット

私が言うように、この答えは完全を期すためだけのものであり、usingwithの以前の提案IDisposablelockキーワードは、99% の確率でより良くなるでしょう。

残念なことに、.Net はこの点で他の多くの最新の OO 言語よりも進んでいますが (私は Java のことを考えています)、依然として RAII がクライアント コード (つまり、using)、一方、C++ では、デストラクタは常にスコープの最後で実行されます。

于 2008-11-02T14:29:16.740 に答える
0

覚えておくべきことは開発者次第であるという事実に私は本当に悩まされてきました.usingせいぜい警告を受け取るだけで、ほとんどの人はわざわざエラーに昇格させることはありません. だから、私はこのようなアイデアをいじっています - それはクライアントに少なくとも物事を正しく行うように強制します. 幸か不幸か、これは閉鎖であるため、クライアントは引き続きリソースのコピーを保持し、後で再度使用しようとすることができますが、このコードは少なくともクライアントを正しい方向にプッシュしようとします...

public class MyLockedResource : IDisposable
{
    private MyLockedResource()
    {
        Console.WriteLine("initialize");
    }

    public void Dispose()
    {
        Console.WriteLine("dispose");
    }

    public delegate void RAII(MyLockedResource resource);

    static public void Use(RAII raii)
    {
        using (MyLockedResource resource = new MyLockedResource())
        {
            raii(resource);
        }
    }

    public void test()
    {
        Console.WriteLine("test");
    }
}

良い使い方:

MyLockedResource.Use(delegate(MyLockedResource resource)
{
    resource.test();
});

使い方が悪い!(残念ながらこれは防げません…)

MyLockedResource res = null;
MyLockedResource.Use(delegate(MyLockedResource resource)
{
    resource.test();
    res = resource;
    res.test();
});
res.test();
于 2008-12-03T13:51:49.327 に答える