C++ 是否可以在C+中创建原子向量或数组+;?

C++ 是否可以在C+中创建原子向量或数组+;?,c++,arrays,multithreading,vector,atomic,C++,Arrays,Multithreading,Vector,Atomic,我有一些代码在一个每秒被激活的线程中使用一个int数组(int[]) 我使用std::mutex中的lock() 然而,我想知道是否有一种方法可以创建一个原子数组(或向量)来避免使用互斥锁?我尝试了两种方法,但编译器总是以某种方式抱怨 我知道有一种方法可以创建原子数组,但这是不一样的。实际上,在CPU级别,有一些指令可以原子地更新int,一个好的编译器会将它们用于std::atomic。相比之下,没有任何指令可以自动更新int向量(对于我所知道的任何体系结构),因此在某个地方必须有某种互斥。你最

我有一些代码在一个每秒被激活的线程中使用一个int数组(
int[]

我使用
std::mutex
中的
lock()

然而,我想知道是否有一种方法可以创建一个原子数组(或向量)来避免使用互斥锁?我尝试了两种方法,但编译器总是以某种方式抱怨


我知道有一种方法可以创建原子数组,但这是不一样的。

实际上,在CPU级别,有一些指令可以原子地更新
int
,一个好的编译器会将它们用于
std::atomic
。相比之下,没有任何指令可以自动更新int向量(对于我所知道的任何体系结构),因此在某个地方必须有某种互斥。你最好让它成为你的互斥体


对于尚未使用互斥体编写代码的未来读者:

您不能创建
int[10]
std::atomic
,因为这会导致一个返回数组的函数,而您不能拥有这些函数。你能做的就是拥有一个
std::atomic

intmain()
{
原子阵列;
}
请注意,编译器/库将在引擎盖下创建一个互斥体,以使其具有原子性。进一步注意,这并不是你想要的。它允许您以原子方式设置整个数组的值

它不允许您读取整个数组,更新一个元素,然后以原子方式写回整个数组。

读取和写入将分别是原子的,但是另一个线程可以进入读取和写入之间


你需要互斥锁

你可以把数组放在原子中,但不能直接放在原子中。与其他答案一样,您可以使用
std::array
。我回答并解释了如何为结构做类似的事情

说到这里,并解释了技术可行性,我必须告诉你一些其他的事情:

请不要那样做 原子变量的威力来自这样一个事实,即一些处理器可以用一条指令执行操作。C++编译器将尝试使原子操作发生在一个指令中。如果失败,它将启动一个总线锁,这就像一个所有东西的全局锁,直到该数组被更新。它相当于锁定程序中所有变量的互斥锁。如果您关心性能,请不要这样做


因此,对于您的情况,互斥不是一个坏主意。至少你可以控制什么是关键的,并提高性能。

你尝试的方法是什么,编译器到底抱怨了什么?顺便说一句,原子的可能重复并不能保证无锁,所以实现可以做类似于
互斥体的事情。
@tobi303我尝试了如下组合:std::atomic myArray={0,0,0}; 或者像这样:std::atomic myArray;还有一些关于无锁编程和性能度量的非常好的CPPCON演讲。简而言之,除非互斥版本不能满足用户的性能期望,否则不要麻烦。如果是这样的话,那么很可能是你的设计错了。原子存储所需时间约为非原子存储所需时间的10倍。如果你正在做一系列的商店,你最好拿着一把锁,在没有原子的情况下做它们。值得一提的是,这个阵列将和巧克力茶壶一样有用。您所能做的就是复制整个阵列或从副本中替换整个阵列。简短而优雅的解释。非常感谢。这就是我寻找的答案。cppref状态和afaik数组都是可复制的,或者我错了?@RichardHodges:是的,我在骑车上班之前写的。当我走出门时,我意识到了这个问题@tobi303:Hmm。根据CPPFreference,可复制类型的数组是可复制的。这可能意味着参考文献中存在错误,或者标准中存在缺陷。当无法获取值时(因为
运算符T
必须返回
int[10]
),要求库允许您实例化
std::atomic
)是毫无意义的。总线锁:您对此有引用吗?当然,在引擎盖下创建互斥将更容易实现(而且性能更高)。如何实现?容易的。
std::atomic
的任何成员函数都不允许直接访问基础值,因此为每个
std::atomic
提供一个互斥体,在每个成员函数的开头锁定互斥体,最后释放它。我有一种感觉,你可能记错了某些体系结构是如何在一个单词上实现原子操作的。@MartinBonner你可能是对的。但我要指出一个非常微妙的点:这与线程安全无关,因为这不是程序必须保证的,这就是问题所在。它是关于原子性及其语义的。原子变量的定义是:它是一个可以执行或不执行操作的变量。它不能处于两者之间的任何状态。这不是关于锁定对变量的访问。但是,我可能又一次记错了这一点,然而,我永远不会对超过16字节的原子进行原子分析。
std::atomic
正好提供了这一点。在内部,可能有中间状态-但它们是任何可定义的行为的C++程序不可观察到的。(如果程序有未定义的行为,就无法进行推理。)我觉得“如果失败,它将启动总线锁”并不完全正确。查看
atomic::load
的签名:您可以指定
内存\u顺序\u xxx
int main()
{
  std::atomic<std::array<int,10>> myArray;
}