我是否需要在c ++线程中使用整数锁定

Sma*_*acL 8 c++ multithreading atomic

如果我在多个线程中访问单个整数类型(例如long,int,bool等等),我是否需要使用同步机制(如互斥锁)来锁定它们.我的理解是,作为原子类型,我不需要锁定对单个线程的访问,但我看到很多代码确实使用了锁定.对这些代码进行概要分析表明使用锁具有显着的性能损失,所以我宁愿不这样做.因此,如果我访问的项目对应于总线宽度整数(例如32位处理器上的4个字节),我是否需要在跨多个线程使用时锁定对它的访问?换句话说,如果线程A在线程B从同一个变量读取的同时写入整数变量X,是否有可能线程B最终将前一个值的几个字节与写入的值的几个字节混合在一起?这种体系结构是否依赖,例如32位系统上的4字节整数是否可以,但64位系统上的8字节整数是不安全的?

编辑:刚看到这个相关的帖子,这有点帮助.

Chr*_*cke 8

您永远不会锁定值 - 您将操作锁定在某个值上.

C&C++没有明确提到线程或原子操作 - 所以看起来它们可能或应该是原子的操作 - 不能保证语言规范是原子的.

它肯定是一个非常不正常的编译器管理int上的非原子读取:如果你有一个读取值的操作 - 可能没有必要保护它.但是,如果它跨越机器字边界,它可能是非原子的.

操作非常简单,m_counter++包括获取,增量和存储操作 - 竞争条件:另一个线程可以在获取之后但在存储之前更改值 - 因此需要通过互斥锁保护 - 或者查找编译器对互锁操作的支持.MSVC具有像_InterlockedIncrement()这样的函数,只要所有其他写操作类似地使用互锁apis来更新内存位置,它就会安全地增加内存位置 - 这比调用一个临界区更轻量级.

GCC具有内部函数__sync_add_and_fetch,也可用于对机器字值执行互锁操作.


Ale*_*x B 5

在 99.99% 的情况下,您必须锁定,即使它是对看似原子变量的访问。由于 C++ 编译器不知道语言级别上的多线程,因此它可以执行大量重要的重新排序。

举个例子:我被自旋锁实现所困扰,其中解锁只是将零分配给volatile整数变量。编译器在锁定下的实际操作之前对解锁操作进行了重新排序,毫不奇怪,导致了神秘的崩溃。

看:

  1. 无锁代码:错误的安全感
  2. 线程不能作为库实现

  • @Joshua,我感觉到一些讽刺吗?如果不是,那么不,这不是编译器错误。没有什么可以阻止编译器在易失性红/写周围重新排序非易失性红/写,它只能在它们之间重新排序易失性读/写。请参阅此问题:http://stackoverflow.com/questions/2535148/volatile-qualifier-and-compiler-reorderings (3认同)

Don*_*ows 5

如果您在一台具有多个内核的机器上,即使写入整数是原子的,您也需要正确地做事情。问题有两方面:

  1. 您需要阻止编译器优化实际写入!(这有点重要。;-))
  2. 您需要内存屏障(不是在 C 中建模的东西)以确保其他内核注意到您已经更改的事实。否则,您将在所有处理器和其他类似的脏细节之间的缓存中纠缠不清。

如果这只是第一件事,您可以标记变量volatile,但第二件事才是真正的杀手,您只会在多核机器上真正看到差异。这恰好是一种比以前更普遍的架构......哎呀!是时候停止草率了;为您的平台使用正确的互斥(或同步或其他)代码,以及如何使内存像您认为的那样工作的所有细节都会消失。