C++ 使用向量作为多线程队列安全吗?

C++ 使用向量作为多线程队列安全吗?,c++,multithreading,c++11,concurrency,C++,Multithreading,C++11,Concurrency,一个向量可以由多个线程写入,而不必担心线程之间可能存在的争用情况,这些线程试图同时推回一个值?底层硬件/操作系统将处理所有事情,并确保程序不会崩溃或出现故障,对吗 只是想用一个不使用锁、互斥体或原子的简单示例进行实验 #include <iostream> #include<thread> #include<vector> using namespace std; std::vector<int> myvector; void append

一个向量可以由多个线程写入,而不必担心线程之间可能存在的争用情况,这些线程试图同时推回一个值?底层硬件/操作系统将处理所有事情,并确保程序不会崩溃或出现故障,对吗

只是想用一个不使用锁、互斥体或原子的简单示例进行实验

#include <iostream>
#include<thread>
#include<vector>

using namespace std;

std::vector<int> myvector;


void append(int value)
{
  myvector.push_back(value);
}


int main()
{

 int val1=1;
 int val2=2;
 int val3=3;

 std::thread t1(append,val1);
 std::thread t2(append,val2);
 std::thread t3(append,val3);

 t1.join();
 t2.join();
 t3.join();



 for(int x=0; x<myvector.size(); ++x)
        std::cout<<myvector[x]<<endl;


 return 0;

}
#包括
#包括
#包括
使用名称空间std;
std::vector myvector;
无效附加(int值)
{
myvector.push_back(值);
}
int main()
{
int val1=1;
int-val2=2;
int val3=3;
std::线程t1(追加,val1);
std::线程t2(追加,val2);
std::线程t3(追加,val3);
t1.join();
t2.连接();
t3.join();

对于(int x=0;x既不<代码> STD::vector < /C>),也没有任何C++库中的容器是线程安全的。当使用任何容器时,您需要使用互斥和条件变量,以便正确地同步线程间容器的访问。


显示的代码是未定义的行为。重复更改线程数和/或增加同一线程推送到向量中的值数,和/或以其他方式使用其他处理负载加载服务器,最终将产生崩溃或错误结果。

无论是
std::vector,还是C++库是线程安全的。当使用任何容器时,您需要使用互斥和条件变量,以便正确地同步线程间容器的访问。

显示的代码是未定义的行为。反复更改线程数和/或增加同一线程推送到向量中的值的数量,和/或以其他方式加载服务器的其他处理负载,最终会产生崩溃或错误结果。

没有一个stl容器是线程安全的,但很容易实现gh建议使用互斥锁对其进行包装。问题不在于多个读取本身,而是当它们写入时,并行执行多个变异操作通常是危险的,因为内部指针和计数器将无法正确更新;并且在发生变异操作时(可能)需要非常小心地进行读取在其他线程上

std::vector是一个特别糟糕的选择,因为整个对象经常面临调整大小的风险,使得迭代器在单线程中甚至失效

std::list变体更好,因为元素是单独分配的,但您仍然必须在任何插入或删除、推送或弹出操作周围设置自己的排除锁定。假设您只有一个list popper,如果您单独知道上次没有将列表弹出为空,那么您可以在弹出之前不使用互斥锁读取后面的内容它在一个互斥锁下运行,以防止其他线程在前端推送新元素。如果上次将列表弹出为空,则在没有互斥锁的情况下,您无法安全地再次获取front()。在这种情况下,您可能需要实现一个信号量,以便在添加新数据时唤醒popper线程。 另一方面,如果您有多个读卡器和多个写卡器,您可以让读卡器使用不同的互斥来成为当前的popper,并且至少可以在不与写卡器发生冲突的情况下读取顶部


另一方面,如果您采取简单的方法,只对容器的所有访问进行互斥,那么它也可能是矢量的。

没有一个stl容器是线程安全的,但是用互斥体包装它们是很容易的。问题不在于这样的多次读取,而是当它们被写入时,通常对stl容器是危险的并行执行多个mutate操作,因为内部指针和计数器无法正确更新;在其他线程上(可能)发生mutate操作时,需要非常小心地读取

std::vector是一个特别糟糕的选择,因为整个对象经常面临调整大小的风险,使得迭代器在单线程中甚至失效

std::list变体更好,因为元素是单独分配的,但您仍然必须在任何插入或删除、推送或弹出操作周围设置自己的排除锁定。假设您只有一个list popper,如果您单独知道上次没有将列表弹出为空,那么您可以在弹出之前不使用互斥锁读取后面的内容它在一个互斥锁下运行,以防止其他线程在前端推送新元素。如果上次将列表弹出为空,则在没有互斥锁的情况下,您无法安全地再次获取front()。在这种情况下,您可能需要实现一个信号量,以便在添加新数据时唤醒popper线程。 另一方面,如果您有多个读卡器和多个写卡器,您可以让读卡器使用不同的互斥来成为当前的popper,并且至少可以在不与写卡器发生冲突的情况下读取顶部


另一方面,如果你采用简单的方法将所有访问都转换为容器,那么它也可能是向量。

简单答案的可能副本是它和你所做的一样安全。C++通常不(几乎从不)。如果你不请求它,会带来很大的开销。你会在写入向量的函数上放置一个互斥锁,然后确保无论有多少线程同时调用push_back,push_back的每个线程调用都会在向量上执行(无论顺序如何),而不会“丢失”吗可能的重复答案是,它和你做的一样安全。C++通常不(几乎从不)。如果你不请求它,会带来很大的开销。你会在写入向量的函数上放置一个互斥锁,然后确保无论有多少线程同时调用push_back,push_back的每个线程调用都会在向量上执行(无论顺序如何),而不会“丢失”吗?非常感谢您的回复,程序是否有可能因为线程太多而崩溃