C++ STL 基础与多线程安全性说明文档
一、STL 简介
STL(Standard Template Library,标准模板库)是 C++ 标准库的重要组成部分,提供了常用的数据结构和算法的泛型实现,极大地提高了代码的复用性和开发效率。
STL 的六大组件
容器(Containers) :如 vector
、list
、deque
、set
、map
、unordered_map
等,用于存储数据。算法(Algorithms) :如 sort
、find
、for_each
等,作用于容器。迭代器(Iterators) :提供一种统一方式遍历容器元素,是容器与算法之间的桥梁。函数对象(Function Objects / Functors) :可作为算法的参数,具有函数调用运算符。适配器(Adapters) :对容器或函数进行包装,如 stack
、queue
、priority_queue
、bind
。分配器(Allocators) :内存分配策略的封装,一般使用默认即可。
二、STL 容器性能对比
常见 STL 容器性能分析
容器 插入 删除 查找 随机访问 是否排序 是否允许重复 vector
尾部 O(1),中间 O(n) O(n) O(n) O(1) 否 是 list
任意位置 O(1)* O(1)* O(n) 否 否 是 deque
头尾 O(1),中间 O(n) O(n) O(n) O(1) 否 是 set
/ map
O(log n)(红黑树) O(log n) O(log n) 否 是 否 unordered_set
/ unordered_map
平均 O(1),最坏 O(n) O(1) O(1) 否 否 否 stack
/ queue
/ priority_queue
O(1) 或 O(log n) O(1) 或 O(log n) 无查找 否 否 N/A
注:list 的插入/删除在给定迭代器位置下是 O(1),但查找该位置是 O(n)
推荐使用场景
场景需求 推荐容器 快速插入删除,频繁操作两端 deque
、list
快速尾部插入和随机访问 vector
快速查找,自动排序 set
、map
快速查找,顺序无关 unordered_set
、unordered_map
需要先进先出 / 后进先出 queue
、stack
需要大顶堆、小顶堆 priority_queue
Demo: 查找性能对比
# include <iostream>
# include <vector>
# include <set>
# include <unordered_set>
# include <chrono> using namespace std;
using namespace std:: chrono; const int N = 1e6 ;
int target = N - 1 ; int main ( ) { vector< int > v; set< int > s; unordered_set< int > us; for ( int i = 0 ; i < N; ++ i) { v. push_back ( i) ; s. insert ( i) ; us. insert ( i) ; } auto t1 = high_resolution_clock:: now ( ) ; auto it1 = find ( v. begin ( ) , v. end ( ) , target) ; auto t2 = high_resolution_clock:: now ( ) ; cout << "vector find time: " << duration_cast< microseconds> ( t2 - t1) . count ( ) << "us" << endl; t1 = high_resolution_clock:: now ( ) ; auto it2 = s. find ( target) ; t2 = high_resolution_clock:: now ( ) ; cout << "set find time: " << duration_cast< microseconds> ( t2 - t1) . count ( ) << "us" << endl; t1 = high_resolution_clock:: now ( ) ; auto it3 = us. find ( target) ; t2 = high_resolution_clock:: now ( ) ; cout << "unordered_set find time: " << duration_cast< microseconds> ( t2 - t1) . count ( ) << "us" << endl; return 0 ;
}
三、STL 容器的多线程安全性分析
STL 容器线程安全原则
✅ 只读共享是安全的(多个线程只读) ❌ 写入操作必须加锁保护 ❌ 多线程同时修改同一个容器是危险的
各容器线程安全性对比
容器 多线程只读 多线程写入 是否自带同步 vector
✅ 安全 ❌ 不安全 ❌ 无同步 map
/ set
✅ 安全 ❌ 不安全 ❌ 无同步 unordered_map
✅ 安全 ❌ 不安全 ❌ 无同步 queue
/ stack
❌ 一般不安全 ❌ 不安全 ❌ 无同步
常见错误示例
# include <vector>
# include <thread> std:: vector< int > v; void writer ( ) { for ( int i = 0 ; i < 10000 ; ++ i) { v. push_back ( i) ; }
} int main ( ) { std:: thread t1 ( writer) ; std:: thread t2 ( writer) ; t1. join ( ) ; t2. join ( ) ; return 0 ;
}
正确写法:加锁保护
# include <vector>
# include <mutex>
# include <thread> std:: vector< int > v;
std:: mutex mtx; void safe_writer ( ) { for ( int i = 0 ; i < 10000 ; ++ i) { std:: lock_guard< std:: mutex> lock ( mtx) ; v. push_back ( i) ; }
}
替代方案与推荐库
目标 替代建议 并发队列 boost::lockfree::queue
、TBB、Folly、MoodyCamel并发哈希表 tbb::concurrent_hash_map
、libcds
自定义多线程容器封装 封装 std::mutex
或使用 shared_mutex
四、最佳实践
所有写操作务必加锁,或使用原子容器 避免在遍历期间修改容器 如果性能要求高,考虑使用专用并发容器库 使用 condition_variable
+ mutex
实现生产者消费者模型