1

私は、達成しようとしていることについての合意を探すのに約 1 時間費やしてきましたが、特定の方向で決定的なものをまだ見つけていません。

私の状況は次のとおりです。

  • マルチスレッド アプリケーション (.NET Web サービス) を使用しています。
  • ロードに無視できない時間がかかるオブジェクトを使用するクラスがあるため、それらを静的クラス メンバーとして維持したいと考えています。
  • これらのオブジェクトを断続的に構築するコードは、失敗する可能性が低い

以前は、静的コンストラクターでこれらのオブジェクトを構築するアプローチを使用していました。これに関する問題は、前述のように、コンストラクターが失敗することがあり、.NET 静的コンストラクターが失敗すると、プロセスが再起動されるまでクラス全体が停止することでした。そのアプローチには二度目のチャンスはありません。

この後、最も直感的に見えるアプローチは、ダブルチェック ロックを使用することでした。ダブルチェックされたロックの悪さについて話し、静的コンストラクターを使用するように言うページがたくさんありますが、これは私がすでに行っていましたが、静的コンストラクターには失敗してクラス全体がダウンする可能性があります。

私が使用しようと考えている実装(もちろん簡略化されたもの)は次のとおりです。すべてのクラスとメンバーの名前は純粋に説明的なものであり、私が実際に使用しているものではありません。このアプローチは問題になるでしょうか?誰でもより良いアプローチを提案できますか?

public class LazyMembers
{
    private static volatile XmlDocument s_doc;
    private static volatile XmlNamespaceManager s_nsmgr;
    private static readonly object s_lock = new object();

    private static void EnsureStaticMembers()
    {
        if (s_doc == null || s_nsmgr == null)
        {
            lock (s_lock)
            {
                if (s_doc == null || s_nsmgr == null)
                {
                    // The following method might fail
                    // with an exception, but if it succeeds,
                    // s_doc and s_nsmgr will be initialized
                    s_doc = LoadDoc(out s_nsmgr);
                }
            }
        }
    }

    public XmlNamespaceManager NamespaceManager
    {
        get
        {
            EnsureStaticMembers();
            return s_nsmgr;
        }
    }

    public XmlDocument GetDocClone()
    {
        EnsureStaticMembers();
        return (XmlDocument)s_doc.Clone();
    }
}
4

1 に答える 1

2

.NET 4.0 を使用している場合はLazy<T>LazyThreadSafetyModeを参照できます (マルチスレッド環境で T のインスタンスをほとんど作成しないかどうかによって異なります。この場合は、参照する必要がありますLazy<T>(Func<T> func, LazyThreadSafetyMode) コンストラクター - here(MSDN)

それ以外の場合 (3.5 以下を使用している場合)、CAS テクニックを使用して、ロックせずに単一のインスタンスを作成できます。

このようなもの:

get {
    if( _instance == null) {
        var singleton = new Singleton();
        if(Interlocked.CompareExchange(ref _instance, singleton, null) != null) {
            if (singleton is IDisposable) singleton.Dispose();
        }
    }
    return _instance;
}

ただし、ここでは LazyThreadSafetyMode.Publications の動作しか実現できません。他のスレッドから見えるインスタンスは 1 つだけですが、作成できるインスタンスはほとんどありません。

また、コード内の null の二重チェックに問題はないはずです。.NET の世界では安全です (少なくとも x86 マシンおよび関連するメモリ モデルでは)。2004 年以前の Java の世界では、いくつかの問題がありました。

于 2010-08-09T09:04:15.520 に答える