C++ STL 基础与多线程安全性说明文档

发布于:2025-05-10 ⋅ 阅读:(19) ⋅ 点赞:(0)

C++ STL 基础与多线程安全性说明文档

一、STL 简介

STL(Standard Template Library,标准模板库)是 C++ 标准库的重要组成部分,提供了常用的数据结构和算法的泛型实现,极大地提高了代码的复用性和开发效率。

STL 的六大组件

  1. 容器(Containers):如 vectorlistdequesetmapunordered_map 等,用于存储数据。
  2. 算法(Algorithms):如 sortfindfor_each 等,作用于容器。
  3. 迭代器(Iterators):提供一种统一方式遍历容器元素,是容器与算法之间的桥梁。
  4. 函数对象(Function Objects / Functors):可作为算法的参数,具有函数调用运算符。
  5. 适配器(Adapters):对容器或函数进行包装,如 stackqueuepriority_queuebind
  6. 分配器(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)

推荐使用场景

场景需求 推荐容器
快速插入删除,频繁操作两端 dequelist
快速尾部插入和随机访问 vector
快速查找,自动排序 setmap
快速查找,顺序无关 unordered_setunordered_map
需要先进先出 / 后进先出 queuestack
需要大顶堆、小顶堆 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_maplibcds
自定义多线程容器封装 封装 std::mutex 或使用 shared_mutex

四、最佳实践

  • 所有写操作务必加锁,或使用原子容器
  • 避免在遍历期间修改容器
  • 如果性能要求高,考虑使用专用并发容器库
  • 使用 condition_variable + mutex 实现生产者消费者模型

网站公告

今日签到

点亮在社区的每一天
去签到