当用两个线程在C/C++中操作不同的数组索引时,是否需要同步
When manipulating different array indices in C/C++ with two threads, is synchronization needed?
假设我有一个定义如下的数组:
volatile char v[2];
我有两个线程(分别用A和B表示)在操作数组v
。如果我确保A、B在任何时候都使用不同的索引,也就是说,如果A现在正在操纵v[i]
,那么B要么什么都不做,要么操纵v[1-i]
。我想知道这种情况是否需要同步?
我已经提到了这个问题,但我认为它在Java中是有限的。我之所以问这个问题,是因为我已经在一个大型项目中与一个奇怪而罕见的错误斗争了好几天,到目前为止,我唯一能解释这个错误的原因是,上述操作需要同步。(由于这个错误非常罕见,我很难证明我的猜测是否属实)
编辑:v
可以读取和修改。
就C++11和C11标准而言,您的代码是安全的。C++11§1.7[介绍内存]/p2,省略了无关注释:
内存位置是标量类型的对象或最大全部具有非零宽度的相邻比特字段的序列。两个或更多执行线程(1.10)可以更新和访问单独的内存位置而不会相互干扰。
char
是一个积分类型,这意味着它是一个算术类型,也意味着volatile char
是一个标量类型,所以v[0]
和v[1]
是单独的存储位置。
C11在§3.14中有类似的定义。
在C++11和C11之前,该语言本身没有线程的概念,因此您只能任由所使用的特定实现摆布。
这可能是编译器错误或硬件限制。
有时,当从内存访问小于32位/64位的变量时,处理器会读取32位,设置相应的8或16位,然后写回整个寄存器。这意味着它也将读取/写入相邻的内存,从而导致数据竞争。
解决方案是
-
使用字节访问指令。它们可能不适用于您的处理器,或者您的编译器不知道如何使用它们。
-
填充元素以避免这种共享。如果目标平台不支持字节访问,编译器应该自动执行。但在数组中,这与内存布局要求相冲突。
- 使整个结构同步
C++03/C++11辩论
在经典C++中,避免/减轻这种行为取决于您。在C++11中,这违反了内存模型的要求,正如其他答案中所述。
只有当您访问并修改同一内存时,才需要处理同步。如果您只是在读取,那么也不需要关心同步。
正如您所说的,每个线程将访问不同的索引,那么您在这里不需要同步。但您需要确保两个线程不应同时修改相同的标记。
- 数组索引的值没有增加
- 并行用于C++17中数组索引范围内的循环
- 数组索引重载错误
- 通过指针与数组引用扩展数组索引序列
- SIGSEGV, 分段错误. 而 printf() 数组索引的值
- 缓冲区溢出 - 数组索引越界(严重)
- 为什么C++数组索引值是有符号的,而不是围绕size_t类型构建的(或者我错了)
- 查找下一个具有真值C++的数组索引
- 在编译时自动生成用于稀疏数组索引的switch语句
- 在数组索引上引发异常
- C++ 将二维数组索引与条件语句中的函数值进行比较
- 平衡数组索引,同时从左和右对数组求和
- 为什么C ,Devstudio,数组索引工作
- 如何对同一数组索引下的结构成员进行排序?
- 我想返回数组索引,而不是数组值
- C++相当于 Python 的:用于数组索引
- 分段错误:为什么这里的数组索引越界了
- 数组索引在地图上不是整数
- 根据用户输入的每个字母添加到数组索引
- C 数组索引