【问题标题】:Determinate when an object not used by any other threads without lock?确定一个对象什么时候没有被任何其他线程使用而没有锁?
【发布时间】:2010-12-29 07:26:22
【问题描述】:

我实现了一个高性能线程安全组件,不使用 lock 语句,出于性能原因仅使用 volatile 和 Interlocked。

我在一个包含线程安全实例的类中有 volatile 引用类型成员。 此实例仅对几个操作是线程安全的,而对另一个则不是。 因此,出于性能原因,在某些情况下,我更喜欢创建新实例而不是更新原始实例,而且它确实工作得更快,尤其是因为我不使用任何锁定语句。

因此 volatile 成员可以随时替换为另一个实例,volatile 关键字确保在多线程环境中不会出现任何问题。

这当然工作得很好,但唯一的问题是旧实例的垃圾收集。在测试我的组件的性能时,我发现它在垃圾收集释放实例上花费了太多时间。

现在我正在寻找一种方法来回收旧实例。问题是我不能在替换时只使用旧实例并重置它的状态,因为可能有另一个线程仍在使用这个实例,我找不到一种方法(没有锁)来保证没有人使用这个实例没有了。

我如何保证没有线程使用没有锁语句的旧实例? (volatile 和 Interlocked 是首选)

谢谢。

【问题讨论】:

  • 使用锁真的会显着降低性能吗?
  • 我真的很喜欢“确定”这个词,一定要记住那个词。
  • 如果您需要对内存管理进行精细控制,托管应用程序可能不是正确的选择。你在做什么锁定是性能损失?
  • @ironic:使用锁时,您失去了多线程最重要的优势之一,因为尽管有线程,但所有请求都是同步处理的,就像您只使用一个线程一样。在我对双核机器的测试中,我发现不使用锁对我的组件来说速度要快 10 倍。 GC 是我想通过的下一个瓶颈,以实现全效率并支持 C# 中接近实时的应用程序。
  • “当使用锁时……所有请求都是同步处理的” -> 你在做/理解错了。

标签: c# .net multithreading volatile recycle


【解决方案1】:

您在这里尝试实现的功能看起来很像引用计数(还记得 COM 吗?)。您可能可以通过递增/递减来做到这一点 - 只需在您的参考旁边保留一个参考计数器。

这种技术的唯一问题是它依赖于对象消费者才能很好地使用对象。这使得代码非常脆弱。

另一个问题是,AFAIK 锁的主要性能问题不是锁本身,而是它所暗示的内存屏障。关键是对 volatile 变量的每次访问都是一样的。换句话说,我不认为你有任何用 volatile 变量替换锁的东西

【讨论】:

  • 我考虑过计数,但问题是获取引用并增加计数器不能是原子操作,因此这可能会产生竞争条件,以防线程只获取引用而不是增加计数器,另一个线程发现计数器为零并回收实例,而前一个线程增加计数并做其他事情。
  • 假设 volatile 在 C# 内存模型中与 Java 具有相同的语义 - 诸如所有 x86 CPU 之类的处理器具有足够强的内存可见性语义,对 volatile 的读取访问在 CPU 级别不需要特殊语义 - 只有写入需要屏障/互锁指令(当然在字节码级别,读取和写入都具有允许重新排序等特殊语义)。
【解决方案2】:

问题是任何线程都可以将对象的引用放到堆栈上,然后用它做任何他们想做的事情。如果不使用整体锁,就无法防止非线程安全操作发生这种情况。

一般来说,您不应该尝试使用 .NET 垃圾收集器 - 最好找出 GC 需要这么长时间的原因,并针对它进行优化(首先不要创建这么多实例,也许是一个 O(n^2) 操作创建大量实例?)而不是尝试以线程安全的方式重用实例。

【讨论】:

  • 很多实例都是设计出来的,应该是这样的。如果我可以回收实例,那么根本不需要垃圾收集。
【解决方案3】:

您是在询问是否存在可以告诉您在多线程应用程序中对对象执行操作是否安全的东西。这就是锁的定义。如果使用 .NET 提供的结构不够快,也许您应该考虑更改为运行速度更快的编译语言。

【讨论】:

  • 我想回收,因为出于性能原因我不想从一开始就使用锁。我不要求完全同步对实例的访问,我只想等到所有其他人都完成了该实例,然后用它做任何我想做的事情,这个定义没有原始锁定义那么通用,我相信我可以无需锁定即可完成。
【解决方案4】:

您可以使对象从死里复活,即当您的对象最终确定时,您实际上可以让它们再次复活。这样做的好处是,在它们生命周期的这一点上,不能有任何对它们的引用,否则它们一开始就永远不会适用于 finalize。有关详细信息,请查看this 文章中的“复活”一章。

现在,如果这真的能为你带来任何表现,或者是否值得这样做,我无法确定 ;-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 2018-11-30
    • 2018-10-19
    • 2012-02-07
    • 2012-06-29
    • 2014-02-28
    相关资源
    最近更新 更多