3

異なるスレッド間で共有される多値ディクショナリに似たグローバル オブジェクトが必要です。

オブジェクトを 1 回だけ作成し (たとえば、データベースからデータを取得する)、別のスレッドで使用したいと考えています。

オブジェクトは、追加のプロパティで簡単に拡張できる必要があります (現在、JobName と URL のみがあります)。

可能であれば、ロックを避けたいと思います。

次の問題に直面しています。

  • 以下に表示されている現在のバージョンは、スレッド セーフではありません。
  • 各キーに複数の値を許可するように Dictionary オブジェクトを拡張したため、ConcurrentDictionary を使用できません。

これは、簡単に変更できるオブジェクト構造です。

    public struct JobData
    {
        public string JobName;
        public string URL;
    }

Dictionary オブジェクトを拡張して、各キーに複数の値を許可しました。

    public class JobsDictionary : Dictionary<string, JobData>
    {
        public void Add(string key, string jobName, string url)
        {
            JobData data;
            data.JobName = jobName;
            data.URL = url;
            this.Add(key, data);
        }
    }

スレッド間で共有される静的クラス。ご覧のとおり、特定のジョブに対して初めて呼び出されたときに、そのジョブの辞書エントリが作成されます。

たとえば、「earnings」に対して初めて呼び出されると、「earnings」ディクショナリ エントリが作成されます。これにより、スレッド セーフの問題が発生します。

public static class GlobalVar
{
    private static JobsDictionary jobsDictionary = new JobsDictionary();
    public static JobData Job(string jobCat)
    {   
        if (jobsDictionary.ContainsKey(jobCat))
            return jobsDictionary[jobCat];
        else
        {
            String jobName;
            String url = null;

            //TODO: get the Data from the Database
            switch (jobCat)
            {
                case "earnings":
                    jobName="EarningsWhispers";
                    url = "http://www.earningswhispers.com/stocks.asp?symbol={0}";
                    break;
                case "stock":
                    jobName="YahooStock";
                    url = "http://finance.yahoo.com/q?s={0}";
                    break;
                case "functions":
                    jobName = "Functions";
                    url = null;
                    break;
                default:
                    jobName = null;
                    url = null;
                    break;
            }
            jobsDictionary.Add(jobCat, jobName, url);
            return jobsDictionary[jobCat];
        }
    }

各スレッドで、次の方法で特定の Job プロパティを取得します。

//Get the Name
string JobName= GlobalVar.Job(jobName).JobName;

//Get the URL
string URL = string.Format((GlobalVar.Job(jobName).URL), sym);

一度「インスタンス化」されたカスタム辞書を作成するにはどうすればよいですか (静的であるため、適切な用語ではないことがわかっています...)、それはスレッドセーフですか?

ありがとう

アップデート

わかりました、これが新しいバージョンです。

switch ステートメントを削除し、すべてのディクショナリ項目を一度にロードすることで、コードを簡素化しました (とにかくすべてが必要です)。

このソリューションの利点は、一度だけロックされることです。つまり、ディクショナリ データが追加されたときです (ロックに入る最初のスレッドがディクショナリにデータを追加します)。スレッドが読み取りのためにディクショナリにアクセスする場合、ディクショナリはロックされません。

jobsDictionary は非公開であるため、スレッドセーフである必要があり、デッドロックが発生することはありません。

public static class GlobalVar
{
    private static JobsDictionary jobsDictionary = new JobsDictionary();   
    public static JobData Job(string jobCat)
    {
        JobData result;
        if (jobsDictionary.TryGetValue(jobCat, out result))
            return result;

        //if the jobsDictionary is not initialized yet...
        lock (jobsDictionary)
        {
            if (jobsDictionary.Count == 0)
            {
                //TODO: get the Data from the Database
                jobsDictionary.Add("earnings", "EarningsWhispers", "http://www.earningswhispers.com/stocks.asp?symbol={0}");
                jobsDictionary.Add("stock", "YahooStock", "http://finance.yahoo.com/q?s={0}");   
                jobsDictionary.Add("functions", "Functions", null);  
            }
            return jobsDictionary[jobCat];
        }
    }
}
4

2 に答える 2

-1

1)シングルトンパターンを使用して1つのインスタンスを作成します(方法の1つは、これまでとstatic同じようにクラスを使用することです)

2)スレッドセーフにするために使用するlockか、アナログです。不要なロックを恐れている場合は、次のようにします。

public object GetValue(object key)
{
    object result;
    if(_dictionary.TryGetValue(key, out result) 
        return result;

     lock(_dictionary)
     {
        if(_dictionary.TryGetValue(key, out result) 
            return result;
        //some get data code
        _dictionary[key]=result;
        return result;
     }
}
于 2012-04-06T10:18:36.277 に答える