代码之家  ›  专栏  ›  技术社区  ›  Trap

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

  •  1
  • Trap  · 技术社区  · 15 年前

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

    我有一些想法,但恐怕不太正确:

    1. 在我浏览列表时锁定正在访问的列表。我不确定这是否有效,因为正在使用的IList可能没有被锁定在另一边进行书写。

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

    3. 最后一个办法是,将每个读访问权放入一个try/catch块,并假装在抛出时什么也没有发生。(想不出一个更糟糕的解决方案是可行的)。

    事先谢谢。

    5 回复  |  直到 15 年前
        1
  •  1
  •   Ash    15 年前

    选项3可能会让人觉得难看,但这看起来类似于Visual Studio Watch Windows使用的方法,我会选择这种方法。

    在Visual Studio中,通常可以在某个列表或集合上设置监视,稍后注意,当监视由于用户或代码状态更改而无法计算某个值时,它只会显示一个异常。

    这是处理这种开放式的可能性范围时最有力的方法。事实是,如果监视代码被设计为尽可能支持多个场景,那么您将无法提前考虑所有场景。更好地处理和呈现异常是下一个最佳方法。

    顺便说一下,有人提到锁定您的数据结构会起作用。如果“其他代码”也不使用锁进行同步,则不是这样。实际上,这两段代码都必须锁定 相同的 同步对象,如果不控制其他代码,则不太可能。(我认为你在问题中提到了这一点,所以我同意。)

        2
  •  4
  •   Bevan    15 年前

    您要使被监视的代码保持“透明”的唯一方法是使监视代码在状态变化时保持健壮。

    一些建议

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

    2. 尽你所能让事情变得更强大——把每一篇文章都放到一个尝试/捕获中可能会让人感觉不舒服,但你可能需要这样做。

        3
  •  1
  •   jrista    15 年前

    虽然我喜欢Bevan为本地读访问复制列表的想法,但是如果列表特别大,这可能不是一个真正可行的选择。

    如果您真的需要无缝、透明、并发地访问这些列表,您应该研究.NET库的并行扩展。它目前作为CTP可用于.NET 2.0到3.5。扩展将与一些附加集合一起正式包含在.NET 4.0中。我认为您会对来自CTP的blockingcollection感兴趣,它将为您提供所需的透明并发访问。显然,与涉及同步的任何线程内容一样,性能也会受到影响,但是这些集合已经得到了相当好的优化。

        4
  •  1
  •   Iravanchi    15 年前

    正如我所理解的,您不希望对被监视的代码有任何依赖性/需求,也不希望对代码的编写方式实施任何约束。

    虽然这是我最喜欢的代码“观察者”方法,但这会使您的应用程序面临非常广泛的代码和行为,从而导致它崩溃。

    所以,正如我之前所说,我的建议是在第一步让观察者“健壮”。您应该为代码中任何地方出错做好准备,因为考虑到“透明性”,许多事情都可能出错!(请注意将您的Try/Catch放在何处,多次进出Try块可能会对性能产生明显影响)

    当您完成了使代码健壮的工作后,接下来的步骤将是使它更可用,并避免出现可能导致异常的情况,比如您提到的“列表”之类的情况。例如,您可以检查被监视的对象,看看它是否是一个列表,而且不太长,首先快速复制它,然后再执行其余操作。这样就消除了大量可能导致代码抛出的可能性。

        5
  •  0
  •   Noon Silk    15 年前

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

    不过,在我看来,我应该避免锁定(因为看起来您的线程只是“观察者”,不应该真正中断)。

    在此基础上,我将尝试处理您确定丢失的情况。这不可能吗?