我在这里需要读写锁吗?

时间:2011-07-14 18:43:22

标签: c++ multithreading thread-safety mutex

我写了一个多线程代码。我不确定,我是否需要读写锁机制。你能不能通过用例告诉我,我必须使用读写锁,或者只是普通的互斥锁。

用例: 1)具有两个变量的类。在执行操作之前,每个线程都可以访问它们。 2)当出现问题时,会更新这些变量以反映错误情况。 因此,读取这些变量的线程可以采取不同的决策(包括中止)

这里,在第二点,我需要更新数据。在第一点,每个线程都将使用数据。所以,我的问题是在读取数据时我必须在更新数据和读锁时使用写锁。 (注意:两个变量都在内存中。只是一个布尔标志和一个字符串)

我很困惑,因为我的两个变量都在记忆中。操作系统在完整性时也要小心。我的意思是当一些线程用互斥锁写入数据时,我可以忍受1或2个线程缺少更新的值。

请告诉我是对还是错?另请告诉我如果必须使用读写锁定,或者仅使用正常的互斥锁。

更新:很抱歉我没有提供平台和编译器名称。我在RHEL 5.0上并使用gcc 4.6。我的平台是x86_64。但我不希望我的代码特定于操作系统,因为我们将很快将代码移植到Solaris 10。

3 个答案:

答案 0 :(得分:4)

首先,忽略那些谈论volatile的其他回答者。 Volatile is almost useless for multithreaded programming,任何错误的安全感都只是 - 假。

现在,您是否需要锁定取决于您对这些变量的处理方式。你至少需要一个内存屏障(锁定意味着一个)。

让我们举个例子:

  • 一个标志是错误标志。如果为零,则继续,否则,您将中止。
  • 另一个标志是诊断代码标志。它给出了错误的确切原因。

在这种情况下,一个选项是执行以下操作:

  • 在没有锁定的情况下读取错误标志,但在读取后读取内存屏障。
  • 发生错误时,请锁定,设置诊断代码和错误标志,然后释放锁定。如果已设置诊断代码,请立即释放锁定。

需要内存屏障,否则编译器(或CPU!)可能会选择为每次读取缓存相同的结果。

当然,如果两个变量的语义不同,答案可能会有所不同。你需要更加具体。

请注意,指定锁和内存障碍的确切机制取决于编译器。 C ++ 0x提供了一种可移植的机制,但很少有编译器完全实现C ++ 0x标准。请指定您的编译器和操作系统以获得更详细的答案。

至于你的输出数据,你几乎肯定需要锁定。尽量避免经常使用这些锁,因为太多的锁争用会导致你的性能下降。

答案 1 :(得分:0)

如果它们是原子变量(C1x stdatomic.h或C ++ 0x atomic),那么您不需要读/写锁。使用早期的C / C ++标准,根本没有可移植的方式使用多个线程,因此您需要了解所使用的实现是如何做的。在大多数实现中,可以使用单个机器指令访问的数据类型是原子的。

请注意,仅使用原子变量是不够的 - 您可能还需要将其声明为volatile以保证编译器不会执行会导致您错过其他线程更新的事情。

答案 2 :(得分:-1)

  

因此,读取这些变量的线程可以采取不同的决策(包括中止)

因此每个线程都需要确保它读取更新的数据。此外,由于变量是共享的,因此您还需要注意竞争条件。

简而言之 - 在读取和写入这些共享变量时,需要使用读/写锁。

查看是否可以使用volatile变量 - 这样可以避免在读取值时使用锁(但写入仍应使用锁)。这只是因为您说 -

  

我的意思是当一些线程用互斥锁写入数据时,我可以忍受1或2个线程缺少更新的值