【OpenHarmony】安全容器模块详解
·
安全容器模块详解
🔒 一句话概括:安全容器就是"带锁的收纳盒",多个线程同时访问也不会出错。
📚 目录
- 什么是安全容器?
- 为什么需要安全容器?
- 安全容器家族一览
- SafeMap - 线程安全字典
- SafeQueue - 线程安全队列
- SafeStack - 线程安全栈
- SafeBlockQueue - 阻塞队列
- SafeBlockQueueTracking - 可追踪阻塞队列
- SortedVector - 自动排序向量
- 使用场景与最佳实践
1. 什么是安全容器?
1.1 通俗理解
想象一个场景:你和同事共用一个文件柜 📁
普通容器(不安全):
你:打开柜子,准备放文件...
同事:同时打开柜子,拿走了你要放的位置的文件...
你:放文件... 💥 冲突了!
安全容器(线程安全):
你:拿钥匙🔑,锁住柜子,放文件,解锁
同事:等你解锁后,再拿钥匙,操作柜子
结果:井然有序 ✅
1.2 技术定义
安全容器 = 标准容器 + 互斥锁(Mutex)
它们在内部自动处理加锁/解锁,让多线程访问变得安全。
2. 为什么需要安全容器?
2.1 多线程的数据竞争问题
2.2 安全容器如何解决
3. 安全容器家族一览
对比总结表
| 容器 | 底层结构 | 线程安全 | 阻塞支持 | 排序 | 主要用途 |
|---|---|---|---|---|---|
| SafeMap | std::map | ✅ | ❌ | 按Key | 多线程键值存储 |
| SafeQueue | std::deque | ✅ | ❌ | ❌ | 多线程FIFO队列 |
| SafeStack | std::deque | ✅ | ❌ | ❌ | 多线程LIFO栈 |
| SafeBlockQueue | std::queue | ✅ | ✅ | ❌ | 生产者-消费者模式 |
| SafeBlockQueueTracking | std::queue | ✅ | ✅ | ❌ | 任务追踪 |
| SortedVector | std::vector | ❌ | ❌ | ✅ | 有序数据存储 |
4. SafeMap - 线程安全字典
4.1 概述
SafeMap 是 std::map 的线程安全封装,适合多线程环境下的键值对存储。
4.2 核心方法详解
插入操作
SafeMap<int, std::string> userMap;
// 方式1: Insert - 如果key已存在则失败
bool success = userMap.Insert(1, "Alice"); // true
bool fail = userMap.Insert(1, "Bob"); // false,key=1已存在
// 方式2: EnsureInsert - 强制插入(覆盖已有值)
userMap.EnsureInsert(1, "Bob"); // 现在 map[1] = "Bob"
查找操作
SafeMap<int, std::string> userMap;
userMap.Insert(1, "Alice");
// 方式1: Find - 安全查找
std::string name;
if (userMap.Find(1, name)) {
std::cout << "找到: " << name << std::endl; // 找到: Alice
}
// 方式2: ReadVal - 直接读取(不存在则返回默认值)
std::string name2 = userMap.ReadVal(1); // "Alice"
std::string name3 = userMap.ReadVal(999); // "" (空字符串,默认值)
遍历操作
SafeMap<int, std::string> userMap;
userMap.Insert(1, "Alice");
userMap.Insert(2, "Bob");
userMap.Insert(3, "Charlie");
// 使用 Iterate 安全遍历
userMap.Iterate([](const int key, std::string& value) {
std::cout << key << ": " << value << std::endl;
// 可以在回调中修改 value
});
Lambda 修改值
SafeMap<int, int> counterMap;
counterMap.Insert(1, 0);
// 使用 Lambda 原子性地修改值
userMap.ChangeValueByLambda(1, [](int& count) {
count++; // 安全地递增
});
4.3 完整示例
#include "safe_map.h"
#include <thread>
#include <iostream>
using namespace OHOS;
void SafeMapDemo() {
SafeMap<std::string, int> scoreMap;
// 线程1: 添加数据
std::thread t1([&scoreMap]() {
for (int i = 0; i < 100; i++) {
scoreMap.Insert("player" + std::to_string(i), i * 10);
}
});
// 线程2: 读取数据
std::thread t2([&scoreMap]() {
for (int i = 0; i < 100; i++) {
int score;
if (scoreMap.Find("player" + std::to_string(i), score)) {
std::cout << "玩家" << i << "分数: " << score << std::endl;
}
}
});
t1.join();
t2.join();
std::cout << "总玩家数: " << scoreMap.Size() << std::endl;
}
5. SafeQueue - 线程安全队列
5.1 概述
SafeQueue 实现了 FIFO(先进先出) 的线程安全队列。
5.2 类结构
5.3 使用示例
#include "safe_queue.h"
using namespace OHOS;
void SafeQueueDemo() {
SafeQueue<int> queue;
// 入队
queue.Push(1);
queue.Push(2);
queue.Push(3);
std::cout << "队列大小: " << queue.Size() << std::endl; // 3
// 出队 (FIFO: 先进先出)
int value;
while (queue.Pop(value)) {
std::cout << "出队: " << value << std::endl;
}
// 输出: 1, 2, 3
}
6. SafeStack - 线程安全栈
6.1 概述
SafeStack 实现了 LIFO(后进先出) 的线程安全栈。
flowchart TB
subgraph SafeStack LIFO
direction TB
Push[Push 入栈] --> Q3[元素3 ← 栈顶]
Q3 --> Q2[元素2]
Q2 --> Q1[元素1]
Q3 -.-> Pop[Pop 出栈]
end
style Push fill:#4caf50,color:#fff
style Pop fill:#f44336,color:#fff
6.2 使用示例
#include "safe_queue.h"
using namespace OHOS;
void SafeStackDemo() {
SafeStack<int> stack;
// 入栈
stack.Push(1);
stack.Push(2);
stack.Push(3);
// 出栈 (LIFO: 后进先出)
int value;
while (stack.Pop(value)) {
std::cout << "出栈: " << value << std::endl;
}
// 输出: 3, 2, 1
}
6.3 SafeQueue vs SafeStack 对比
flowchart LR
subgraph SafeQueue
direction LR
A1[Push 1] --> A2[Push 2] --> A3[Push 3]
A3 --> A4[Pop → 1, 2, 3]
end
subgraph SafeStack
direction LR
B1[Push 1] --> B2[Push 2] --> B3[Push 3]
B3 --> B4[Pop → 3, 2, 1]
end
7. SafeBlockQueue - 阻塞队列
7.1 概述
SafeBlockQueue 是一个有界阻塞队列,核心特性:
- 🔒 线程安全:内部自动加锁
- ⏸️ 阻塞等待:队列满时 Push 会等待,队列空时 Pop 会等待
- 📏 容量限制:创建时指定最大容量
7.2 类结构
7.3 阻塞 vs 非阻塞方法
| 方法 | 队列满时 | 队列空时 | 返回值 |
|---|---|---|---|
Push(elem) | 阻塞等待 | - | void |
Pop() | - | 阻塞等待 | T |
PushNoWait(elem) | 返回 false | - | bool |
PopNotWait(elem) | - | 返回 false | bool |
7.4 生产者-消费者模式示例
#include "safe_block_queue.h"
#include <thread>
#include <iostream>
using namespace OHOS;
void ProducerConsumerDemo() {
SafeBlockQueue<int> taskQueue(5); // 容量为5
// 生产者线程
std::thread producer([&taskQueue]() {
for (int i = 1; i <= 10; i++) {
std::cout << "生产任务: " << i << std::endl;
taskQueue.Push(i); // 队列满时会阻塞
}
});
// 消费者线程
std::thread consumer([&taskQueue]() {
for (int i = 0; i < 10; i++) {
int task = taskQueue.Pop(); // 队列空时会阻塞
std::cout << "消费任务: " << task << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
producer.join();
consumer.join();
}
7.5 工作流程图
8. SafeBlockQueueTracking - 可追踪阻塞队列
8.1 概述
SafeBlockQueueTracking 在 SafeBlockQueue 基础上增加了任务追踪功能:
- 📊 追踪未完成任务数
- ⏱️ Join 等待所有任务完成
8.2 核心方法
| 方法 | 说明 |
|---|---|
Push(elem) | 入队,未完成任务数 +1 |
OneTaskDone() | 标记一个任务完成,未完成数 -1 |
Join() | 阻塞等待,直到所有任务完成 |
GetUnfinishTaskNum() | 获取未完成任务数 |
8.3 工作流程
8.4 使用示例
#include "safe_block_queue.h"
#include <thread>
#include <iostream>
#include <functional>
using namespace OHOS;
using Task = std::function<void()>;
void TaskTrackingDemo() {
SafeBlockQueueTracking<Task> taskQueue(10);
// 添加任务
for (int i = 1; i <= 5; i++) {
taskQueue.Push([i]() {
std::cout << "执行任务 " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
}
std::cout << "未完成任务数: " << taskQueue.GetUnfinishTaskNum() << std::endl; // 5
// 工作线程
std::thread worker([&taskQueue]() {
Task task;
while (taskQueue.PopNotWait(task)) {
task(); // 执行任务
taskQueue.OneTaskDone(); // 标记完成
}
});
// 等待所有任务完成
taskQueue.Join();
std::cout << "所有任务已完成!" << std::endl;
worker.join();
}
9. SortedVector - 自动排序向量
9.1 概述
SortedVector 是一个自动保持有序的向量,插入元素时自动排序。
⚠️ 注意:SortedVector 不是线程安全的!如需多线程使用,请自行加锁。
9.2 类结构
classDiagram
class SortedVector~TYPE,AllowDuplicate~ {
-std::vector~TYPE~ vec_
+Add(item) ssize_t
+IndexOf(item) ssize_t
+OrderOf(item) size_t
+Erase(index) iterator
+Merge(vector) size_t
+Clear()
+Size() size_t
+IsEmpty() bool
+operator[](index) TYPE
+Front() TYPE
+Back() TYPE
+Begin() iterator
+End() iterator
}
note for SortedVector "AllowDuplicate 模板参数:\ntrue = 允许重复元素\nfalse = 不允许重复"
9.3 模板参数说明
// 允许重复元素 (默认)
SortedVector<int, true> vec1; // 或 SortedVector<int>
vec1.Add(1);
vec1.Add(1); // ✅ 允许,结果: [1, 1]
// 不允许重复元素
SortedVector<int, false> vec2;
vec2.Add(1);
vec2.Add(1); // ❌ 失败,返回 -1
9.4 核心方法
Add - 添加元素(自动排序)
SortedVector<int> vec;
vec.Add(5); // [5]
vec.Add(2); // [2, 5]
vec.Add(8); // [2, 5, 8]
vec.Add(3); // [2, 3, 5, 8]
// 返回插入位置的索引
ssize_t index = vec.Add(6); // 返回 3,结果: [2, 3, 5, 6, 8]
IndexOf - 查找元素
SortedVector<int> vec;
vec.Add(10);
vec.Add(20);
vec.Add(30);
ssize_t idx1 = vec.IndexOf(20); // 返回 1
ssize_t idx2 = vec.IndexOf(99); // 返回 -1 (NOT_FOUND)
OrderOf - 获取应插入位置
SortedVector<int> vec; // [10, 20, 30]
vec.Add(10);
vec.Add(20);
vec.Add(30);
size_t pos = vec.OrderOf(25); // 返回 2 (应该插入到索引2的位置)
Merge - 合并向量
SortedVector<int> vec1;
vec1.Add(1);
vec1.Add(3);
vec1.Add(5); // [1, 3, 5]
std::vector<int> vec2 = {2, 4, 6};
vec1.Merge(vec2); // [1, 2, 3, 4, 5, 6]
9.5 完整示例
#include "sorted_vector.h"
#include <iostream>
using namespace OHOS;
void SortedVectorDemo() {
// 创建不允许重复的有序向量
SortedVector<int, false> scores;
// 添加分数
scores.Add(85);
scores.Add(92);
scores.Add(78);
scores.Add(92); // 重复,添加失败
scores.Add(88);
std::cout << "分数排名:" << std::endl;
for (size_t i = 0; i < scores.Size(); i++) {
std::cout << i + 1 << ". " << scores[i] << std::endl;
}
// 输出:
// 1. 78
// 2. 85
// 3. 88
// 4. 92
// 查找分数
ssize_t idx = scores.IndexOf(88);
if (idx != SortedVector<int, false>::NOT_FOUND) {
std::cout << "88分排名第 " << idx + 1 << " 位" << std::endl;
}
// 获取最高分和最低分
std::cout << "最低分: " << scores.Front() << std::endl; // 78
std::cout << "最高分: " << scores.Back() << std::endl; // 92
}
9.6 二分查找原理
SortedVector 使用二分查找实现高效的查找和插入:
时间复杂度:
| 操作 | 复杂度 |
|---|---|
| Add | O(n) - 需要移动元素 |
| IndexOf | O(log n) - 二分查找 |
| OrderOf | O(log n) - 二分查找 |
| operator[] | O(1) - 直接访问 |
10. 使用场景与最佳实践
10.1 选择指南
10.2 典型使用场景
| 容器 | 典型场景 |
|---|---|
| SafeMap | 缓存系统、会话管理、配置存储 |
| SafeQueue | 消息队列、事件分发、日志收集 |
| SafeStack | 撤销/重做功能、表达式求值 |
| SafeBlockQueue | 线程池任务队列、生产者-消费者模式 |
| SafeBlockQueueTracking | 批量任务处理、等待所有任务完成 |
| SortedVector | 排行榜、有序数据检索 |
10.3 最佳实践
✅ 推荐做法
// 1. 使用 Find 而不是 ReadVal 检查元素是否存在
SafeMap<int, std::string> map;
std::string value;
if (map.Find(key, value)) {
// key 存在,使用 value
}
// 2. 使用 PopNotWait 进行非阻塞检查
SafeBlockQueue<Task> queue(100);
Task task;
if (queue.PopNotWait(task)) {
// 有任务,处理
} else {
// 队列空,做其他事
}
// 3. 使用 EnsureInsert 确保值被更新
map.EnsureInsert(key, newValue); // 不管key是否存在都会成功
❌ 避免的错误
// 错误1: 在循环中频繁调用 Size()
// ❌ 每次调用都要加锁
for (int i = 0; i < map.Size(); i++) { ... }
// ✅ 改用 Iterate
map.Iterate([](const K& key, V& value) { ... });
// 错误2: 忘记调用 OneTaskDone
SafeBlockQueueTracking<Task> queue(10);
Task task = queue.Pop();
task();
// ❌ 忘记调用 OneTaskDone(),Join() 会永远等待!
// ✅ 正确做法
task();
queue.OneTaskDone();
// 错误3: 在多线程中使用 SortedVector 不加锁
// SortedVector 不是线程安全的!
std::mutex mtx;
SortedVector<int> vec;
{
std::lock_guard<std::mutex> lock(mtx);
vec.Add(value); // ✅ 手动加锁
}
10.4 性能对比
xychart-beta
title "各容器操作时间复杂度"
x-axis ["SafeMap", "SafeQueue", "SafeBlockQueue", "SortedVector"]
y-axis "时间复杂度 (1=O(1), 2=O(log n), 3=O(n))" 1 --> 3
bar [2, 1, 1, 3]
| 容器 | 插入 | 查找 | 删除 |
|---|---|---|---|
| SafeMap | O(log n) | O(log n) | O(log n) |
| SafeQueue | O(1) | O(n) | O(n) |
| SafeBlockQueue | O(1) | - | O(1) |
| SortedVector | O(n) | O(log n) | O(n) |
📊 API 速查表
SafeMap
| 方法 | 说明 | 返回值 |
|---|---|---|
Insert(key, value) | 插入(key存在则失败) | bool |
EnsureInsert(key, value) | 强制插入(覆盖) | void |
Find(key, value) | 查找 | bool |
ReadVal(key) | 读取值 | V |
Erase(key) | 删除 | void |
Clear() | 清空 | void |
Size() | 大小 | int |
IsEmpty() | 是否为空 | bool |
Iterate(callback) | 遍历 | void |
FindOldAndSetNew(key, old, new) | 查找并替换 | bool |
SafeQueue / SafeStack
| 方法 | 说明 | 返回值 |
|---|---|---|
Push(elem) | 入队/入栈 | void |
Pop(elem) | 出队/出栈 | bool |
Empty() | 是否为空 | bool |
Size() | 大小 | int |
Clear() | 清空 | void |
Erase(elem) | 删除指定元素 | void |
SafeBlockQueue
| 方法 | 说明 | 阻塞 |
|---|---|---|
Push(elem) | 入队 | ✅ 队列满时阻塞 |
Pop() | 出队 | ✅ 队列空时阻塞 |
PushNoWait(elem) | 非阻塞入队 | ❌ |
PopNotWait(elem) | 非阻塞出队 | ❌ |
Size() | 大小 | - |
IsEmpty() | 是否为空 | - |
IsFull() | 是否已满 | - |
SortedVector
| 方法 | 说明 | 返回值 |
|---|---|---|
Add(item) | 添加(自动排序) | ssize_t (索引) |
IndexOf(item) | 查找索引 | ssize_t |
OrderOf(item) | 获取应插入位置 | size_t |
Erase(index) | 删除 | iterator |
Merge(vector) | 合并 | size_t |
operator[](index) | 访问元素 | TYPE& |
Front() / Back() | 首/尾元素 | TYPE& |
🎯 总结
mindmap
root((安全容器))
线程安全
SafeMap
SafeQueue
SafeStack
SafeBlockQueue
SafeBlockQueueTracking
非线程安全
SortedVector
阻塞支持
SafeBlockQueue
SafeBlockQueueTracking
任务追踪
SafeBlockQueueTracking
记住这三点:
- SafeMap/SafeQueue/SafeStack = 普通容器 + 自动加锁
- SafeBlockQueue = 生产者-消费者模式的最佳选择
- SortedVector 不是线程安全的,需要自己加锁!
更多推荐
所有评论(0)