通过C#中的反射访问数据时的并发问题

时间:2009-10-11 23:33:16

标签: c# .net reflection concurrency locking

我正在编写一个库,可用于显示某些正在运行的代码的内部状态(主要是公共和私有的字段和属性)。在不同的线程中访问对象以将其信息放入窗口供用户查看。问题是,有时我走的是一个长期的IList,其结构可能会发生变化。程序中的某些代码被“监视”可能会添加一个新项目,甚至更糟糕的是删除一些。这当然会导致整个事情崩溃。

我想出了一些想法,但我担心它们不太正确:

  1. 在我走路时锁定正在访问的列表。我不确定这是否会起作用,因为使用的IList可能没有被锁定在另一边写作。

  2. 让被监视的代码知道我的存在,并提供一些允许同步的接口。 (我真的希望它完全透明)。

  3. 作为最后的手段,将每个读取访问权限放入try / catch块中,并假装它抛出时没有任何反应。 (想不出一个真正有用的丑陋的解决方案。)

  4. 提前致谢。

5 个答案:

答案 0 :(得分:4)

你要对被监控的代码保持“透明”的唯一方法是在面对状态变化时使监控代码变得健壮。

一些建议

  1. 不要走共享列表 - 尽快(尽快)将列表的副本复制到本地List实例中。一旦你有了一个本地(非共享)实例列表,没有人可以使用该列表。

  2. 尽可能让事情变得健壮 - 将每一个读物放入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)

锁定列表将起作用,因为 正在被修改,正如您通过崩溃观察到的那样:)

然而,对我来说,我会避免锁定(因为看起来你的线程似乎只是'观察者'并且不应该真正中断)。

在此基础上,我会尝试处理您确定遗漏事物的案例。这不可能吗?