C++ 我可以制作线程安全的std::atomic<;向量<;int>>;?

C++ 我可以制作线程安全的std::atomic<;向量<;int>>;?,c++,multithreading,c++11,vector,C++,Multithreading,C++11,Vector,我有一个函数需要执行n=1000次。此函数执行蒙特卡罗式模拟,并返回int作为结果。我想并行运行nthreads=4。每当线程完成一个周期时,它都应该将结果放入std::vector。 因此,在1000个循环之后,我得到了一个1000ints的向量,可以通过统计来检查 由于std::vector不是线程安全的,所以我考虑了std::mutex(这肯定会起作用) 但我想知道我是否可以声明一个向量是原子的,从而绕过互斥体? 是否可以有一个std::atomic?我可以在上面使用push_back等吗

我有一个函数需要执行
n=1000次。此函数执行蒙特卡罗式模拟,并返回
int
作为结果。我想并行运行
nthreads=4
。每当线程完成一个周期时,它都应该将结果放入
std::vector
。 因此,在1000个循环之后,我得到了一个1000
int
s的向量,可以通过统计来检查

由于
std::vector
不是线程安全的,所以我考虑了
std::mutex
(这肯定会起作用)

但我想知道我是否可以声明一个向量是原子的,从而绕过互斥体?
是否可以有一个
std::atomic
?我可以在上面使用
push_back
等吗?

原子可以用简单的可复制类型实例化。向量不是这样的类型。

您不需要这样做。如果

  • 你读东西
  • 你可以写不同的对象
因此,只要确保创建一个大小为
n=1000
的向量,并根据线程编号(1到4)为线程分配元素0-249、250-499等

因此,每个线程都计算
n/nthreads
元素。

C++11§29.5/1说

有一个通用类模板原子。模板参数T的类型应该是可复制的(3.9)

微不足道的可复制意味着什么

§3.9

标量类型、普通可复制类类型(第9条)、此类类型的数组以及这些类型的cv限定版本(3.9.3)统称为普通可复制类型

对于类类型(其中
std::vector
为):

普通可复制类是指:

  • 没有非平凡的复制构造函数
  • 没有非平凡的移动构造函数
  • 没有非平凡的复制赋值运算符
  • 没有非平凡的移动赋值运算符
  • 有一个平凡的析构函数
根据这个列表,
std::vector
是不可复制的,因此不能使用
std::atomic

因为您事先知道大小,并且不需要使用需要将向量重新分配到不同位置的方法(如
推回)
。您可以使用
std::vector::resize
或size构造函数预分配和预构造所需的
int
s。因此,您的并发线程不需要对向量本身进行操作,而是对元素进行操作

如果不同线程无法访问同一元素,则不存在争用条件


intk[1000]
也是如此,它非常容易复制。但您不需要这样做,因为线程不会更改数组/向量/列表本身,而是更改元素。

问题不是答案。请将问题写在OP上,作为对问题的注释。问题是一个C型数组,如
int k[1000]
一个“可复制的类型”?
k
只是一个指针。指针是可复制的。但是我不知道使用这个表是否是线程安全的,因为
k
是一个普通的指针,但是
k[5]
可以写成
*(k+5)
k+5
是一个不同的指针,但我真的不确定。您可以从
std
检查
是否可复制。您通常会为线程安全容器编写自己的
threadsafe\u vector
类型。是否编译了std::atomic?我无法在这台机器上尝试。。。我只是想补充一点,如果你从一开始就知道你将有1000次执行,你的容器将存储1000个结果,那么你为什么要使用动态容器呢?我知道std::vector在其实现中使用了数组,如果您在一开始就预留了足够的空间,则不需要重新分配(因此使用std::array不会带来任何性能提升)。在将向量的一部分分配给线程之前,适当调整向量的大小是非常重要的-任何大小调整都绝对不是线程安全的。但是,即使这样做,您仍然需要在读写器之间同步。特别是,但不仅仅是因为不能保证对
int
的访问在所有体系结构上都是原子的,除非您使用
atomic\u int
std::atomic