我在wpf应用程序中使用单例模式,但怀疑如何使其适用于多个线程。
我有一个名为Monitor的类,它维护一个“设置”列表,供不同的“设备”使用。大纲如下所示。
我正在做的主线程 Monitor.getMonitor.register(watchlist)或Monitor.getMonitor.unregister(...)取决于用户输入,我有一个DispatchTimer运行每200ms执行一次 Monitor.getMonitor.update()
public class Monitor
{
private Hashtable Master; //key=device, value=list of settings to watch
private static Monitor instance = new Monitor();
private Monitor() {}
public static Monitor getMonitor()
{
return instance;
}
public void register(watchlist){...}
public void unregister(...){...}
public void update(){...}
}
register()/ unregister()对hastable执行add / remove。 update()只是从哈希表中读取东西。
根据设备和设置的数量,update()将迭代hastable及其内容,获取最新值。 主线程可能经常调用注册和注销,我希望gui保持响应。这是一个很好的方法吗?
我是否锁定哈希表,围绕添加/删除和迭代,或者只是使用try catch(ala优雅地失败)来更新更新中的迭代部分以捕获哈希表可能进入的任何奇怪状态(无锁定)或者是否存在一些更好的方法来做到这一点(如果更新失败没有概率..无论如何将再次在200ms运行)。
不确定发生了什么,导致代码没有真正显示任何问题本身让我有点不安,因为它似乎是错误的。谢谢你的任何建议......
答案 0 :(得分:11)
请参阅我的article on singleton implementations以使单身人士自己获取线程安全。
是的,当您修改或迭代哈希表时,您需要锁定。您可以使用ReaderWriterLock
(或者在.NET 3.5中优先ReaderWriterLockSlim
)一次允许多个读者。如果你在迭代时需要做很多工作,你可以随时锁定,复制,解锁,然后处理副本 - 只要工作不介意副本稍微陈旧。
(如果你使用的是.NET 2.0+,我建议使用Dictionary<TKey, TValue>
等通用集合而不是Hashtable
。我还建议你重命名你的方法。 NET约定。该代码目前有一个独特的Java口音;)
答案 1 :(得分:0)
是的,你应该锁定每个操作:
public class Monitor
{
private Hashtable Master; //key=device, value=list of settings to watch
...
private object tableLock = new object();
public void register(watchlist)
{
lock(tableLock) {
// do stuff
}
}
}
您不应该考虑使用try / catch块 - 不应将异常视为“正常”情况,并且您最终可能会遇到损坏的对象状态而没有任何异常。
答案 2 :(得分:0)
有多少行?除非update()循环花费很长时间来进行迭代,否则我可能会锁定。如果主线程可能会进行大量的注册/取消注册调用,那么更新可能会重复失败 - 如果连续20或30次调用失败,那有问题吗?
该代码对我来说没问题。我可能会让课堂密封。我还使用了一个打字字典而不是一个Hashtable。