C#使用来自两个不同线程的单例

时间:2009-06-09 19:53:15

标签: c# multithreading singleton

我在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运行)。

不确定发生了什么,导致代码没有真正显示任何问题本身让我有点不安,因为它似乎是错误的。谢谢你的任何建议......

3 个答案:

答案 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。