我正在编写一个库,可用于显示某些正在运行的代码的内部状态(主要是公共和私有的字段和属性)。在不同的线程中访问对象以将其信息放入窗口供用户查看。问题是,有时我走的是一个长期的IList,其结构可能会发生变化。程序中的某些代码被“监视”可能会添加一个新项目,甚至更糟糕的是删除一些。这当然会导致整个事情崩溃。
我想出了一些想法,但我担心它们不太正确:
在我走路时锁定正在访问的列表。我不确定这是否会起作用,因为使用的IList可能没有被锁定在另一边写作。
让被监视的代码知道我的存在,并提供一些允许同步的接口。 (我真的希望它完全透明)。
作为最后的手段,将每个读取访问权限放入try / catch块中,并假装它抛出时没有任何反应。 (想不出一个真正有用的丑陋的解决方案。)
提前致谢。
答案 0 :(得分:4)
你要对被监控的代码保持“透明”的唯一方法是在面对状态变化时使监控代码变得健壮。
一些建议
不要走共享列表 - 尽快(尽快)将列表的副本复制到本地List实例中。一旦你有了一个本地(非共享)实例列表,没有人可以使用该列表。
尽可能让事情变得健壮 - 将每一个读物放入try / catch中可能会感觉很讨厌,但你可能需要这样做。
答案 1 :(得分:1)
虽然我喜欢Bevan想要复制列表以进行本地读取访问,但如果列表特别大,那么这可能不是一个真正可行的选择。
如果您确实需要对这些列表进行无缝,透明的并发访问,那么您应该查看.NET扩展的.NET扩展库。它目前可用于.NET 2.0到3.5作为CTP。扩展将正式包含在.NET 4.0中以及一些其他集合中。我想您会对CTP中的BlockingCollection感兴趣,它会为您提供所需的透明并发访问。显然,与涉及同步的任何线程化内容相比,性能都会受到影响,但是这些集合已经得到了相当好的优化。
答案 2 :(得分:1)
选项3可能会觉得难看,但这看起来与Visual Studio观察窗口使用的方法类似,我会选择这种方法。
在Visual Studio中,您通常可以在某个列表或集合上设置监视,稍后会注意,当由于用户或代码状态更改而无法评估某个值时,监视会显示异常。
在处理这种开放式可能性时,这是最强大的方法。事实是,如果您的观看代码旨在支持尽可能多的场景,您将无法提前考虑所有情况。很好地处理和呈现异常是下一个最好的方法。
顺便说一句,其他人提到锁定数据结构会起作用。如果“其他代码”也没有使用锁进行同步,则情况并非如此。实际上,这两段代码必须锁定相同的同步对象,如果不控制其他代码,则极不可能。 (我想你在你的问题中提到这一点,所以我同意。)
答案 3 :(得分:1)
据我了解,您不希望对正在监视的代码有任何依赖性/要求,也不希望对代码的编写方式施加任何约束。
虽然这是我最喜欢的编码“观察者”的方法,但这会导致应用程序面对非常广泛的代码和行为,这会导致它崩溃。
所以,正如我之前所说,我的建议是让观察者在第一步“健壮”。您应该为代码中的任何地方出错做好准备,因为考虑到“透明度”,许多事情可能会出错! (小心放置try / catch的位置,多次进入和离开try块会对性能产生明显的影响)
当你完成使代码健壮的时候,接下来的步骤就是让它更有用,避开可能导致异常的情况,比如你提到的“列表”。例如,您可以检查被监视的对象并查看它是否是列表,并且它不会太长,首先快速复制它然后完成剩下的工作。通过这种方式,您可以消除大量可能导致代码抛出的概率。
答案 4 :(得分:0)
锁定列表将起作用,因为 正在被修改,正如您通过崩溃观察到的那样:)
然而,对我来说,我会避免锁定(因为看起来你的线程似乎只是'观察者'并且不应该真正中断)。
在此基础上,我会尝试处理您确定遗漏事物的案例。这不可能吗?