我需要在读取对象时进行锁定吗?

38

我正在编写一个程序,其中有一个对象被多个线程共享:

  • A)多个写线程向对象中写入数据(所有线程都运行相同的功能)
  • B)一个读取线程每 5 秒钟访问该对象
  • C)一个读取线程在有用户请求时访问该对象

很显然,在向对象中写入内容时需要对其进行锁定,因为我们不希望多个线程同时写入该对象。

我的问题是:

  1. 在从对象中读取内容时,是否也需要将其锁定?
  2. 如果我们只在写入时锁定对象,是否仅需要一个临界区即可;但是如果我们在读取或写入时锁定对象,是否需要一个互斥量?

我之所以提出这个问题,是因为在 Microsoft Office 中,两个 Word 实例不能以读/写模式访问同一个文档;但是在以读/写模式打开文档时,可以打开另一个 Word 实例以只读模式访问该文档。在多线程中是否也适用相同的逻辑?


3
看看关系型数据库是如何做到这一点的很有用,它们是共享数据访问的大师。 - skaffman
5个回答

27

正如Ofir所写 - 如果您尝试从另一个线程正在修改的对象中读取数据,您可能会得到一些不一致的状态数据。

但是 - 如果您确定该对象未被修改,则可以从多个线程读取它。一般来说,您所问的问题更或多或少是读者写者问题 - 参见http://en.wikipedia.org/wiki/Readers-writers_problem

最后 - 临界区是一个抽象的术语,可以使用互斥锁或监视器来实现。在Java或C#中,用于临界区的语法糖(synchronized、lock)在内部使用监视器。


7

当读取一个对象时,是否也需要将其锁定?

如果同时还有其他内容可以对其进行写入,则需要。如果只有另一个读取操作,则不需要。在您的情况下,我会建议锁定。

如果我们只在写入时锁定对象,那么关键部分就足够了;但是如果我们在读取或写入时锁定对象,则需要互斥锁吗?

不需要,您可以对两者都使用关键部分。互斥锁比关键部分具有更多功能(例如,命名互斥锁可从多个进程中使用),但我认为您在这里不需要这些功能。


谢谢。我现在意识到,临界区可以用于不同的子程序,只要这些子程序属于同一个进程。 - Andy

5

这是必要的,否则(除非操作是原子的),你可能会读取中间状态。

你可能希望同时允许多个读者,这需要一种(有点)更复杂的锁。


写操作是原子性的,但非常感谢您的回答。 - Andy

4
  1. 这取决于您如何使用和阅读它。如果您的读取是原子性的(即不会被写入打断),而且读取线程与写入线程没有依赖关系,那么您可能可以跳过读锁。但如果您的“读取”操作需要一些时间并且需要进行大量对象交互,则应为其加锁以供读取。

  2. 如果您的阅读时间不长(即不会过长地延迟写入线程),则关键部分应该足够。


0

只有当两个进程可以更改相同的数据库表元素时才需要锁定。 当您想要读取数据时,它始终是安全的。您读取一致性数据库的数据。更改数据的进程具有一致的阴影版本,并且在保存时将覆盖当前数据。但是,如果您正在运行依赖于数据库元素中关键值的读取过程,则应查找指示这些值可能会被更改的锁定。因此,您的读取将延迟直到锁定消失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接