另一个同步问题......我希望你们不要生气;)
假设以下场景:一个中央数据结构(非常大,所以我真的不想让它变成不可变的,并且每当发生变化时都要复制它。我甚至不想在内存中保留多个副本),多个读取器线程以只读方式访问该数据结构,以及一个写入器线程,使数据结构在后台保持最新。
我目前正在同步对数据结构的所有访问,这样可以正常工作(没有同步效果,没有死锁)。我不喜欢这种方法的是,大多数时候我有很多读者线程处于活动状态,编写器线程只是偶尔活跃。现在,读者线程完全没有必要等待其他读者线程完成。只要编写器线程当前没有写入,他们就可以轻松地并行访问数据结构。
有没有一种优雅而优雅的方式来解决这种情况?
编辑:非常感谢您的答案和链接!让我添加另一个简短且相关的问题:如果在读者的关键部分中执行的代码只需要很短的时间(就像只是哈希表查找),是否值得考虑实现您描述的技术之一或者是序列化在这种情况下锁的效果不是那么糟糕?可伸缩性和性能非常重要。你觉得怎么样?
编辑2:我刚刚查看了单个writer / mulitple reader的一个实现 - 锁定,这个实现使用监视器来同步WaitToRead方法中的一些代码。这不会导致我想要首先避免的相同序列化效果吗? (仍假设要同步的代码短而快)
答案 0 :(得分:9)
在RTL(sysutils)中有一个用于此目的的类: TMultiReadExclusiveWriteSynchroniser
它非常易于使用。您不需要像读者或作者那样严格地对线程进行分类。只需在线程中调用“BeginRead”或“BeginWrite”即可启动线程安全操作。调用“EndRead”或“EndWrite”完成操作。
答案 1 :(得分:5)
您正在寻找的内容(以及vartec所描述的内容)被称为Reader(s)-Writer-Lock。
答案 2 :(得分:3)
您可以在msdn magazine和excerpt from Programming applications for MS windows找到有关解决此问题的详细说明。
答案 3 :(得分:2)
使用Reader-Writer锁可以解决问题。所有读者阅读完毕后,多个读者可以访问数据库,并且作者会获得锁定。
然而,这可能会导致作者永远无法访问源,因为总有新读者想要访问。这可以通过在作者想要访问时阻止新读者来解决:作者具有更高的优先级。一旦源上的所有读者都完成阅读,作者就可以访问。
答案 4 :(得分:1)
每当作家想要访问时,你将入局读者排队(让他们等待条件),等待活跃的读者完成,写作,并在完成后让入队读者访问。
答案 5 :(得分:1)
没有人能够真正回答你的问题,序列化是否会严重影响应用程序的性能 - 你必须自己对其进行分析,结果将在很大程度上取决于线程,内核和特定工作负载的数量。
但请注意,使用比关键部分更聪明的同步(例如reader-writer-lock)可能会引入可能难以调试和修复的starvation问题。你真的需要仔细研究增加的吞吐量是否超过了潜在的问题。另请注意,吞吐量实际上可能没有增加,特别是如果锁定的代码非常短且快。有一个nice article by Jeffrey Richter实际上包含这个引用:
性能即使没有对ReaderWriterLock的争用,它的性能也非常慢。例如,对其AcquireReaderLock方法的调用比调用Monitor的Enter方法要花费大约五倍的时间。
这当然适用于.NET,但基本原则也适用。
答案 6 :(得分:0)
读写器锁是您所需要的。 Tutorial有一个描述,但我确定有人将此作为标准添加到Delphi中。可能值得检查D2009已经没有了。