我有一个名为Configuration
的类,它有几个属性,将使用从数据库加载的值进行更新
我在OnDataChanged
构造函数中有一个数据触发事件Configuration
,其中eventhandler订阅了一个私有方法。
多个线程使用相同的Configuration
实例。
如果在数据库表中更新了某些内容,则会激活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; } }
}
答案 0 :(得分:0)
正如其他人所评论的那样,您的代码可能不是线程安全的。使线程安全的最简单方法是创建一个私有对象并使用lock
关键字 - 假设您没有使用任何async
代码。
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();
}
}
}
如果您有多个需要一起更改的设置,那么这很难看。如果someSetting1
和someSetting2
的值彼此互补(例如用户名和密码对),则您有一个竞争条件,其中OnDataChanged
可以在两次调用之间调用SomeSetting1
和SomeSetting2
,导致您的调用代码变得不协调。如果这是一个问题,那么您需要将锁定移到Configuration
类之外。
一种方法就是每次访问时锁定配置单例对象 - 无论是更新它还是从中读取一组值。避免lock
完全依赖于引用的原子性的另一种方法是让您的Configuration
类在子类中存储一组值并向该类添加公共访问器。 OnDataChanged将换出当前值类,并且调用代码将获取当前值,然后从该不可变实例获取他们想要的所有值:
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);