2017-09-07 4 views
-1

私はConfigurationというクラスを持っていますが、これはデータベースからロードされた値で更新されるいくつかのプロパティを持っています。
私は、イベントハンドラがプライベートメソッドに加入しているConfigurationコンストラクタにデータトリガイベントOnDataChangedを持っています。
Configurationの同じインスタンスが複数のスレッドによって使用されます。C#スレッドセーフでインスタンスを更新していますか?

OnDataChangedイベントが発生し、プライベートメソッドが呼び出され、このプライベートメソッド内で、Configurationプロパティをデータベースの最新のデータで更新するため、すでにインスタンスを使用しているスレッドが更新されたデータを持つ。

これはスレッドセーフですか?
どうすればこのスレッドセーフにすることができますか?私はロックを使用していません。

編集:

追加するサンプルコード:

他の人がコメントしたように
public class Configuration 
{ 
    private GeneralConfiguration _generalConfiguration; 
    private AccountConfiguration _accountConfiguration; 
    private readonly SqlTableDependency<Model> _dependency; 
    public Configuration() 
    { 
     _dependency = new SqlTableDependency<Model>("connectionstring", "dbo.Configuration"); 
     _dependency.OnChanged += _dependency_OnChanged; 
     _dependency.Start(); 
    } 

    private void _dependency_OnChanged(object sender, RecordChangedEventArgs<Model> e) 
    { 
     Init(); 
    } 

    private Configuration Init() 
    { 
     DataAccess da = new DataAccess(); 
     List<string> configs = da.GetConfigData(); 
     _generalConfiguration = JsonConvert.Deserialize<GeneralConfiguration>(configs[0]); 
     _accountConfiguration = JsonConvert.Deserialize<AccountConfiguration>(configs[1]); 
     return this; 
    } 

    public GeneralConfiguration GeneralConfiguration { get { return _generalConfiguration; } } 

    public AccountConfiguration AccountConfiguration { get { return _accountConfiguration; } } 
} 
+1

コードサンプルを提供してください – mayu

+0

_ "私はロックを使用していません" _確かにあなたにヒントを与えますか? – MickyD

+0

自分で開く問題は、使用しているデータの種類によって多少異なります。 .Netの少なくともいくつかのバージョンでは、すべての変数の読み込み/書き込みがアトミックであるわけではありません。つまり、別のスレッドが書き込んでいる間に1つのスレッドが読み取れば、読み取り側は古い値の一部である値を取得し、非原子的参照の例)。 [変数参照の不可分性](https://msdn.microsoft.com/en-us/library/aa691278(v = vs.71).aspx)適切なロックを実装するだけです。 – hatchet

答えて

0

、あなたのコードは、おそらくスレッドセーフではありません。スレッドセーフにする最も簡単な方法は、プライベートオブジェクトを作成し、asyncコードを使用していないと仮定してlockキーワードを使用することです。

public class Configuration { 
    private object sync = new object(); 
    private int someSetting1; 
    public int SomeSetting1 { 
     get { 
     lock (sync) { 
      return someSetting1; 
     } 
     } 
    } 

    private decimal someSetting2; 
    public decimal SomeSetting2 { 
     get { 
     lock (sync) { 
      return someSetting2; 
     } 
     } 
    } 

    private void OnDataChanged() { 
     lock (sync) { 
     someSetting1 = loadFromDatabase(); 
     someSetting2 = loadFromDatabase(); 
     } 
    } 
} 

ここでは、一緒に変更する必要がある複数の設定がある場合は、これは醜いです。 someSetting1someSetting2の値が互いに補完関係にある場合(たとえば、ユーザー名とパスワードのペアなど)、OnDataChangedSomeSetting1SomeSetting2の間の呼び出しで呼び出され、呼び出しコードが不適切な値になる競合状態が発生します。 。これが問題の場合は、Configurationクラスの外部でロックを移動する必要があります。

1つのアプローチは、アクセスするたびにコンフィギュレーションシングルトンオブジェクトをロックすることです。更新するか値セットを読み込むかにかかわらず、参照のアトミック性を全く頼りにしない別のアプローチは、Configurationクラスが子クラスに一連の値を格納し、そのクラスにパブリックアクセサを追加することです。 OnDataChangedは、現在の値クラスをスワップアウトだろう、と呼び出し元のコードは、現在の1だったものは何でもつかむと、彼らがしたかったすべての値を取得することを不変のインスタンスから:

public class Configuration { 
    public class Values { 
     public int SomeSetting1 { get; } 
     public int SomeSetting2 { get; } 
    } 
    private Values currentValues; 
    public Values CurrentValues { 
     get { 
     return currentValues; 
     } 
    } 
    private void OnDataChanged() { 
     Values newValues = new Values(getValuesFromDatabase()); 
     currentValues = newValues; 
    } 
} 

電話番号がセットのためにこのような何かをするだろう値の:

var values = configuration.CurrentValues; 
doSomething(values.SomeSetting1, values.SomeSetting2); 
+0

ありがとうTim。上のサンプルコードでは、OnDataChangedイベントがトリガされたときに、private varのInit関数を更新しています。これにより、インスタンス自体以外のプロパティ値をスレッドが更新できないようになります。私の現在のデザインでは、すべてのバックグラウンドワーカープロセスは、サービス開始時にデータベースから設定値を読み込みます(設定はDIコンテナを介してSingletonとしてインスタンス化されます)。一度設定値がDBで変更されたら、私のサービス。代わりに、サービスが動的に変更を知りたいと思っています。助言がありますか? – coold

関連する問題