另一个同步问题......我希望你们不要生气;)

假设以下场景:一个中央数据结构(非常大,所以我真的不想让它变成不可变的,并且每当发生变化时都要复制它。我甚至不想在内存中保留多个副本),多个读取器线程以只读方式访问该数据结构,以及一个写入器线程,使数据结构在后台保持最新。

我目前正在同步对数据结构的所有访问,这样可以正常工作(没有同步效果,没有死锁)。我不喜欢这种方法的是,大多数时候我有很多读者线程处于活动状态,编写器线程只是偶尔活跃。现在,读者线程完全没有必要等待其他读者线程完成。只要编写器线程当前没有写入,他们就可以轻松地并行访问数据结构。

有没有一种优雅而优雅的方式来解决这种情况?

编辑:非常感谢您的答案和链接!让我添加另一个简短且相关的问题:如果在读者的关键部分中执行的代码只需要很短的时间(就像只是哈希表查找),是否值得考虑实现您描述的技术之一或者是序列化在这种情况下锁的效果不是那么糟糕?可伸缩性和性能非常重要。你觉得怎么样?

编辑2:我刚刚查看了单个writer / mulitple reader的一个实现 - 锁定,这个实现使用监视器来同步WaitToRead方法中的一些代码。这不会导致我想要首先避免的相同序列化效果吗? (仍假设要同步的代码短而快)

有帮助吗?

解决方案

在RTL(sysutils)中有一个用于此目的的类: TMultiReadExclusiveWriteSynchroniser

它非常易于使用。您不需要像读者或作者那样严格地对线程进行分类。只需拨打“BeginRead”即可。或“BeginWrite”在用于启动线程安全操作的线程中。呼叫“EndRead”或“EndWrite”或完成操作。

其他提示

您正在寻找的内容(以及vartec描述的内容)称为 Reader(s)-Writer -Lock

有关解决此问题的详细说明,请参阅 msdn magazine 摘自编程应用程序对于MS窗口

使用Reader-Writer锁可以解决问题。所有读者阅读完毕后,多个读者可以访问数据库,并且作者会获得锁定。

然而,这可能会导致作者永远无法访问源,因为总有新读者想要访问。这可以通过在作者想要访问时阻止新读者来解决:作者具有更高的优先级。一旦源上的所有读者都完成阅读,作者就可以访问。

每当作家想要访问时,你将入局读者排队(让他们等待条件),等待活跃的读者完成,写作,并在完成后让入队读者访问。

没有人能够真正回答你的问题,序列化是否会极大地影响应用程序的性能 - 你必须自己对其进行分析,结果将在很大程度上取决于线程,内核和特定工作负载的数量。

但是请注意,使用比关键部分更聪明的同步,例如reader-writer-lock,可以引入饥饿问题可能难以调试和修复。你真的需要仔细研究增加的吞吐量是否超过了潜在的问题。另请注意,吞吐量实际上可能没有增加,特别是如果锁定的代码非常短且快。有一个杰弗里里希特的好文章实际上包含这个引用:

  

性能即使没有对ReaderWriterLock的争用,它的性能也非常慢。例如,对其AcquireReaderLock方法的调用比调用Monitor的Enter方法要花费大约五倍的时间。

这当然适用于.NET,但基本原则也适用。

读写器锁是您所需要的。 教程有一个描述,但我确定有人将此作为标准添加到Delphi中。可能值得检查D2009已经没有了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top