2009-03-06 29 views
5

另一个同步的问题...我希望你们不要生气;)同步多个阅读器,单个作者?

假定存在以下情况:一个中心数据结构(非常大的,所以我真的不希望把它一成不变的复制我甚至不想在内存中保留多个副本),多个读取器线程访问该数据结构只读,一个写入器线程保持数据结构在后台最新。

我目前同步所有访问的数据结构,这只是罚款(不同步效应,不死锁)。我不喜欢这种方法的是,大多数情况下,我有很多读者线程处于活动状态,写入程序线程只是偶尔活动。现在阅读器线程完全不需要等待其他阅读器线程完成。只要写入线程当前未写入,他们可以轻松地并行访问数据结构。

有没有一个很好的和优雅的方式来解决这种情况?

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

编辑2:我刚刚查看了一个作家/多读者的一个实现 - 锁定和此实现使用监视器来同步WaitToRead方法中的一些代码。这不会造成我想避免的序列化效应吗? (仍然假定要同步的代码是短而快的)

回答

9

有在RTL为此类(sysutils的):TMultiReadExclusiveWriteSynchroniser

这是非常容易使用。您不需要严格将读者或作者的线索分类。只需在用于启动线程安全操作的线程中调用“BeginRead”或“BeginWrite”即可。调用“EndRead”或“EndWrite”完成操作。

1

每当作者想要访问,你排入传入的读者(让他们等待条件),等待活跃的读者完成,写,当完成让让入队读者访问。

2

使用读写器锁可以解决问题。多位读者可以访问数据库,一旦所有读者完成阅读,作者就会获得锁定。

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

0

读写器锁是你需要的。 Tutorial有一个描述,但我相信有人在Delphi中加入这个标准。可能值得检查D2009已经没有了。

1

没有人能真正回答你的问题,序列化是否会影响应用程序的性能非常 - 你必须配置文件,为自己,其结果将在线程,核心的数量和具体的工作量大大依赖。

但请注意,使用比关键部分(如读取器 - 写入器锁定)更聪明的同步可引入starvation可能难以调试和修复的问题。你真的需要看看增加的吞吐量是否超过了潜在的问题。还要注意的是,吞吐量实际上可能并没有增加,特别是如果锁定的代码非常短而且速度很快。有实际包含这句话一nice article by Jeffrey Richter

性能即使没有争一ReaderWriterLock,它的性能是非常缓慢的。例如,对其AcquireReaderLock方法的调用比对Monitor的Enter方法的调用执行时间要长五倍。

这是对.NET的当然,但基本原则也适用。

+0

Jeffrey Richter正在讨论.NET库中ReaderWriterLock的实现。他本人在同一篇文章中介绍了这种锁的高效实现。但是,谢谢!我有点害怕没有明确的答案;) – jpfollenius 2009-03-06 10:38:00

+1

@Smasher:确实。然而,在VCL中实施MREW存在问题,人们并不真正相信它。 Jeffrey Richter一直在做这个东西超过15年,我相信他的判断和实施。试着通知你正在进入的内容。 – mghie 2009-03-06 10:46:02