-1

クラスを適切に定義し、安全に使用するにはどうすればよいでしょうか。すべての Web サイト訪問者が何千もの同時呼び出しを行っている場合、安全にスレッド化することを意味します。

私は以下のようなものを自分で作ったが、それは適切に構築されているのだろうか

public static class csPublicFunctions
{
    private static Dictionary<string, clsUserTitles> dicAuthorities;

    static csPublicFunctions()
    {
        dicAuthorities = new Dictionary<string, clsUserTitles>();
        using (DataTable dtTemp = DbConnection.db_Select_DataTable("select * from myTable"))
        {
            foreach (DataRow drw in dtTemp.Rows)
            {
                clsUserTitles tempCLS = new clsUserTitles();
                tempCLS.irAuthorityLevel = Int32.Parse(drw["Level"].ToString());
                tempCLS.srTitle_tr = drw["Title_tr"].ToString();
                tempCLS.srTitle_en = drw["Title_en"].ToString();
                dicAuthorities.Add(drw["authorityLevel"].ToString(), tempCLS);
            }
        }
    }

    public class clsUserTitles
    {
        private string Title_tr;
        public string srTitle_tr
        {
            get { return Title_tr; }
            set { Title_tr = value; }
        }

        private string Title_en;
        public string srTitle_en
        {
            get { return Title_en; }
            set { Title_en = value; }
        }

        private int AuthorityLevel;
        public int irAuthorityLevel
        {
            get { return AuthorityLevel; }
            set { AuthorityLevel = value; }
        }
    }

    public static clsUserTitles returnUserTitles(string srUserAuthority)
    {
        return dicAuthorities[srUserAuthority];
    }
}

辞書は 1 回だけ初期化されます。後で更新を追加削除する必要はありません。

4

6 に答える 6

3

コードをざっと見てみると、最初の問題は公開されている辞書にあるように思えますdicAuthorities。辞書はスレッドセーフではありません。そのディクショナリで何をしたいかによっては、ディクショナリへのアクセスを規制する何かを実装する必要があります。この関連する質問を参照してください。

辞書アクセスをスレッドセーフにしますか?

于 2013-01-10T22:22:39.713 に答える
3

ディクショナリは、スレッド セーフな読み取りをサポートします。MSDNからの証拠は次のとおりです。

コレクションが変更されない限り、ディクショナリは複数のリーダーを同時にサポートできます。それでも、コレクションの列挙は本質的にスレッドセーフな手順ではありません。列挙が書き込みアクセスと競合するまれなケースでは、列挙全体の間、コレクションをロックする必要があります。読み取りおよび書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

そのため、そこからデータを読み取ることだけを計画している場合は、うまくいくはずです。しかし、あなたの辞書が一度だけ入力され、アプリケーションの作業中に変更されることはないとは思いません。この場合、このスレッドの他のすべての人は正しいです。この辞書へのアクセスを同期する必要があり、ConcurrentDictionaryオブジェクトを使用するのが最善です。

さて、デザイン自体について一言言いたいと思います。ユーザー間で共有データを保存する場合は、代わりにそのような目的のために設計されたASP.NET キャッシュを使用してください。

于 2013-01-10T22:32:03.527 に答える
3

他の人が言ったように、Dictionary<TKey,TValue>本質的にスレッドセーフではありません。ただし、使用シナリオが次の場合:

  1. 起動時に辞書を埋める
  2. アプリケーションの実行中にその辞書をルックアップとして使用する
  3. 起動後に値を追加または削除しない

あなたが元気であるべきより。

ただし、.net 4.5 を使用する場合は、#3 を明示的にすることをお勧めします。ReadOnlyDictionary

したがって、実装は次のようになります (コーディング スタイルをより C# に適したものに変更しました)。

private static readonly ReadOnlyDictionary<string, UserTitles> authorities;

static PublicFunctions()
{
    Dictionary<string, UserTitles> authoritiesFill = new Dictionary<string, clsUserTitles>();
    using (DataTable dtTemp = DbConnection.db_Select_DataTable("select * from myTable"))
    {
        foreach (DataRow drw in dtTemp.Rows)
        {
            UserTitles userTitle = new UserTitles
            {
              AuthorityLevel = Int32.Parse(drw["Level"].ToString()),
              TitleTurkish = drw["Title_tr"].ToString();
              TitleEnglish = drw["Title_en"].ToString();
            }
            authoritiesFill.Add(drw["authorityLevel"].ToString(), userTitle);
        }
    }
    authorities = new ReadOnlyDictionary<string, UserTitles>(authoritiesFill);
}

また、宣言自体に修飾子を追加しましたreadonly。これにより、実行時に別の辞書に置き換えられないことを確認できるからです。

于 2013-01-10T22:33:21.623 に答える
2

いいえ、あなたのコードはスレッドセーフではありません。

  • [編集は適用されません-静的コンストラクター内で設定/作成されます]辞書(システムダウンの回答で指摘されているように)は、更新中はスレッドセーフではありません。ディクショナリは読み取り専用ではないため、時間の経過とともに変更されないことを保証する方法はありません。
  • [編集は適用されません - 静的コンストラクター内で設定/作成] 初期化はロックによって保護されないため、同時に複数の初期化を行うことになります
  • エントリは変更可能です。そのため、各エントリの一貫した値を取得するかどうかを判断するのは非常に困難です
  • [編集は適用されません - 静的コンストラクターでのみ変更されます] 読み取り専用ではないディクショナリを保持するフィールド - ディクショナリ自体へのポインタをキャッシュしない場合、コードによっては一貫性のないデータになる可能性があります。

補足: C# のコーディング ガイドラインに従い、大文字の MySpecialClass で始まるクラスを呼び出し、クラスの目的を反映した名前 (または明確なサンプル名) を付けるようにしてください。

編集:辞書の唯一の初期化は静的コンストラクター内にあるため、私のポイントのほとんどは適用されません。これにより、スレッドセーフの観点から初期化が安全になります。静的コンストラクター内の初期化は、「最初に使用する前」の非決定的な瞬間に発生することに注意してください。これにより、予期しない動作が発生する可能性があります。つまり、DB へのアクセスで間違った「現在の」ユーザー アカウントが使用される可能性があります。

于 2013-01-10T22:37:00.833 に答える
0

あなたの質問に対する答えはノーです。スレッドセーフではありません。Dictionaryスレッドセーフなコレクションではありません。スレッド セーフな辞書を使用する場合は、ConcurrentDictionaryを使用します。

csPublicFunctionsそれに加えて、呼び出し内でデータベース接続を処理する方法に依存するため、スレッドセーフかどうかを判断するのは困難ですDbConnection.db_Select_DataTable

于 2013-01-10T22:25:16.433 に答える
0

public のみでスレッドセーフの問題はありませんDictionary。はい、辞書の入力はスレッドセーフです。しかし、このディクショナリの別の変更は、スレッド セーフではありません。上に書いたように -ConcurrentDictionary助けることができます。

あなたのクラスclsUserTitlesもスレッドセーフではないという別の問題。読み取りのみに使用する場合は、各プロパティ セッターをプライベートclsUserTitlesにすることができます。clsUserTitlesそして、これらのプロパティをclsUserTitlesコンストラクターから初期化します。

于 2013-01-10T22:36:36.607 に答える