@ohos-graphics/stability-code-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -0
- package/SKILL.md +518 -0
- package/bin/install.js +165 -0
- package/config/rules.yaml +445 -0
- package/config/whitelist.yaml +52 -0
- package/package.json +40 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
- package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
- package/references/PROBLEM_TEMPLATE.md +65 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
- package/references/REPORT_TEMPLATE.csv +5 -0
- package/references/REPORT_TEMPLATE.md +132 -0
- package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
- package/references/RULE_INDEX.md +101 -0
- package/references/RULE_TEMPLATE.md +192 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
- package/scripts/add-rule.py +423 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_ConcurrencyStability_001"
|
|
3
|
+
name: "多线程场景线程安全设计缺失"
|
|
4
|
+
category: "并发稳定性"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 多线程场景线程安全设计缺失
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
在多线程场景下,共享数据的访问如果没有做好线程安全设计,会导致数据竞争、内存不一致等问题,引发程序崩溃、数据损坏等严重稳定性问题。必须合理使用锁或其他同步机制保护共享数据。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### ❌ 问题代码
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 错误示例1:全局变量无锁保护
|
|
22
|
+
int g_counter = 0;
|
|
23
|
+
|
|
24
|
+
void IncrementCounter()
|
|
25
|
+
{
|
|
26
|
+
g_counter++; // 危险:多线程并发访问导致数据竞争
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 错误示例2:成员变量无锁保护
|
|
30
|
+
class SharedQueue {
|
|
31
|
+
public:
|
|
32
|
+
void Push(int value) {
|
|
33
|
+
queue_.push_back(value); // 危险:无锁保护的并发写入
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
int Pop() {
|
|
37
|
+
int value = queue_.front(); // 危险:无锁保护的并发读取
|
|
38
|
+
queue_.pop_front();
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private:
|
|
43
|
+
std::deque<int> queue_; // 多线程共享队列
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// 错误示例3:单例模式无锁保护
|
|
47
|
+
class Singleton {
|
|
48
|
+
public:
|
|
49
|
+
static Singleton* GetInstance() {
|
|
50
|
+
if (instance_ == nullptr) { // 危险:竞态条件
|
|
51
|
+
instance_ = new Singleton();
|
|
52
|
+
}
|
|
53
|
+
return instance_;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private:
|
|
57
|
+
static Singleton* instance_;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// 错误示例4:引用计数无锁保护
|
|
61
|
+
class RefCounted {
|
|
62
|
+
public:
|
|
63
|
+
void AddRef() {
|
|
64
|
+
refCount_++; // 危险:无锁保护的引用计数增加
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
void Release() {
|
|
68
|
+
if (--refCount_ == 0) { // 危险:无锁保护的引用计数减少和判断
|
|
69
|
+
delete this;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private:
|
|
74
|
+
int refCount_ = 1;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// 错误示例5:检查-执行模式无锁保护
|
|
78
|
+
std::map<int, std::string> g_cache;
|
|
79
|
+
std::mutex g_mutex;
|
|
80
|
+
|
|
81
|
+
std::string GetValue(int key) {
|
|
82
|
+
auto it = g_cache.find(key); // 危险:在锁外访问共享数据
|
|
83
|
+
if (it != g_cache.end()) {
|
|
84
|
+
return it->second;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
std::lock_guard<std::mutex> lock(g_mutex);
|
|
88
|
+
g_cache[key] = LoadFromDisk(key);
|
|
89
|
+
return g_cache[key];
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### ✅ 修复方案
|
|
94
|
+
|
|
95
|
+
```cpp
|
|
96
|
+
// 正确示例1:使用std::mutex保护全局变量
|
|
97
|
+
#include <mutex>
|
|
98
|
+
|
|
99
|
+
int g_counter = 0;
|
|
100
|
+
std::mutex g_counterMutex;
|
|
101
|
+
|
|
102
|
+
void IncrementCounter()
|
|
103
|
+
{
|
|
104
|
+
std::lock_guard<std::mutex> lock(g_counterMutex);
|
|
105
|
+
g_counter++; // 安全:有锁保护
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 正确示例2:使用线程安全队列
|
|
109
|
+
class SharedQueue {
|
|
110
|
+
public:
|
|
111
|
+
void Push(int value) {
|
|
112
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
113
|
+
queue_.push_back(value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
int Pop() {
|
|
117
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
118
|
+
if (queue_.empty()) {
|
|
119
|
+
return -1; // 返回错误码表示队列为空
|
|
120
|
+
}
|
|
121
|
+
int value = queue_.front();
|
|
122
|
+
queue_.pop_front();
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private:
|
|
127
|
+
std::deque<int> queue_;
|
|
128
|
+
std::mutex mutex_;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// 正确示例3:使用std::call_once实现线程安全单例
|
|
132
|
+
class Singleton {
|
|
133
|
+
public:
|
|
134
|
+
static Singleton* GetInstance() {
|
|
135
|
+
std::call_once(initFlag_, []() {
|
|
136
|
+
instance_ = new Singleton();
|
|
137
|
+
});
|
|
138
|
+
return instance_;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private:
|
|
142
|
+
static Singleton* instance_;
|
|
143
|
+
static std::once_flag initFlag_;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// 正确示例4:使用std::atomic实现引用计数
|
|
147
|
+
class RefCounted {
|
|
148
|
+
public:
|
|
149
|
+
void AddRef() {
|
|
150
|
+
refCount_.fetch_add(1, std::memory_order_relaxed);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void Release() {
|
|
154
|
+
if (refCount_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
|
155
|
+
delete this;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private:
|
|
160
|
+
std::atomic<int> refCount_{1};
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// 正确示例5:完整的锁保护
|
|
164
|
+
std::map<int, std::string> g_cache;
|
|
165
|
+
std::mutex g_mutex;
|
|
166
|
+
|
|
167
|
+
std::string GetValue(int key) {
|
|
168
|
+
{
|
|
169
|
+
std::lock_guard<std::mutex> lock(g_mutex);
|
|
170
|
+
auto it = g_cache.find(key);
|
|
171
|
+
if (it != g_cache.end()) {
|
|
172
|
+
return it->second;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
std::string value = LoadFromDisk(key);
|
|
177
|
+
|
|
178
|
+
std::lock_guard<std::mutex> lock(g_mutex);
|
|
179
|
+
g_cache[key] = value;
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 正确示例6:使用读写锁优化读多写少场景
|
|
184
|
+
#include <shared_mutex>
|
|
185
|
+
|
|
186
|
+
class ThreadSafeCache {
|
|
187
|
+
public:
|
|
188
|
+
std::string Get(int key) {
|
|
189
|
+
std::shared_lock<std::shared_mutex> lock(rwMutex_);
|
|
190
|
+
auto it = cache_.find(key);
|
|
191
|
+
if (it != cache_.end()) {
|
|
192
|
+
return it->second;
|
|
193
|
+
}
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void Set(int key, const std::string& value) {
|
|
198
|
+
std::unique_lock<std::shared_mutex> lock(rwMutex_);
|
|
199
|
+
cache_[key] = value;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private:
|
|
203
|
+
std::map<int, std::string> cache_;
|
|
204
|
+
mutable std::shared_mutex rwMutex_;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// 正确示例7:使用thread_local避免同步开销
|
|
208
|
+
thread_local int t_threadCounter = 0;
|
|
209
|
+
|
|
210
|
+
void ProcessInThread()
|
|
211
|
+
{
|
|
212
|
+
t_threadCounter++; // 安全:thread_local,每个线程独立计数,无需同步
|
|
213
|
+
DoWork();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 正确示例8:精确的memory_order控制
|
|
217
|
+
std::atomic<bool> dataReady_{false};
|
|
218
|
+
std::atomic<int> sharedData_{0};
|
|
219
|
+
|
|
220
|
+
void Producer()
|
|
221
|
+
{
|
|
222
|
+
sharedData_.store(42, std::memory_order_relaxed); // 数据写入
|
|
223
|
+
dataReady_.store(true, std::memory_order_release); // release标记数据已准备好
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
void Consumer()
|
|
227
|
+
{
|
|
228
|
+
while (!dataReady_.load(std::memory_order_acquire)) { // acquire等待数据就绪
|
|
229
|
+
std::this_thread::yield();
|
|
230
|
+
}
|
|
231
|
+
int data = sharedData_.load(std::memory_order_relaxed); // 安全:release-acquire同步
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 正确示例9:使用atomic_store_explicit/load_explicit
|
|
235
|
+
std::atomic<std::shared_ptr<NodeList>> childrenList_;
|
|
236
|
+
|
|
237
|
+
void UpdateChildren(std::shared_ptr<NodeList> newList)
|
|
238
|
+
{
|
|
239
|
+
std::atomic_store_explicit(&childrenList_, newList, std::memory_order_release);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
std::shared_ptr<NodeList> GetChildren() const
|
|
243
|
+
{
|
|
244
|
+
return std::atomic_load_explicit(&childrenList_, std::memory_order_acquire);
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## 检测范围
|
|
249
|
+
|
|
250
|
+
检查以下多线程场景:
|
|
251
|
+
|
|
252
|
+
1. 全局变量在多线程环境下的访问
|
|
253
|
+
2. 类成员变量在多线程环境下的访问
|
|
254
|
+
3. 单例模式的初始化
|
|
255
|
+
4. 引用计数的增减操作
|
|
256
|
+
5. 共享容器的并发访问
|
|
257
|
+
6. 检查-执行(check-then-act)模式
|
|
258
|
+
|
|
259
|
+
## 检测要点
|
|
260
|
+
|
|
261
|
+
1. 识别共享数据:全局变量、静态变量、类成员变量
|
|
262
|
+
2. 识别并发场景:线程函数、回调、异步任务
|
|
263
|
+
3. 检查是否有同步机制:mutex、lock_guard、atomic、condition_variable
|
|
264
|
+
4. 检查锁的粒度和正确性
|
|
265
|
+
5. 排除NOPROTECT标记的代码
|
|
266
|
+
|
|
267
|
+
### memory_order使用说明
|
|
268
|
+
|
|
269
|
+
精确的内存序控制可以提高性能并确保正确的同步:
|
|
270
|
+
|
|
271
|
+
- **memory_order_relaxed**:仅保证原子性,无顺序约束
|
|
272
|
+
- 适用场景:纯统计计数、不需要同步的数据
|
|
273
|
+
- 示例:`counter.fetch_add(1, std::memory_order_relaxed)`
|
|
274
|
+
|
|
275
|
+
- **memory_order_release**:写操作,确保之前的写操作对其他线程可见
|
|
276
|
+
- 适用场景:发布数据、状态标记
|
|
277
|
+
- 示例:`dataReady_.store(true, std::memory_order_release)`
|
|
278
|
+
|
|
279
|
+
- **memory_order_acquire**:读操作,确保看到release之前的所有写操作
|
|
280
|
+
- 适用场景:消费数据、等待状态
|
|
281
|
+
- 示例:`while (!dataReady_.load(std::memory_order_acquire))`
|
|
282
|
+
|
|
283
|
+
- **memory_order_acq_rel**:同时具有release和acquire语义
|
|
284
|
+
- 适用场景:读-修改-写操作(如fetch_sub)
|
|
285
|
+
- 示例:`refCount_.fetch_sub(1, std::memory_order_acq_rel)`
|
|
286
|
+
|
|
287
|
+
- **atomic_store_explicit/atomic_load_explicit**:更明确的原子操作
|
|
288
|
+
- 适用场景:std::atomic<std::shared_ptr> 等复杂类型
|
|
289
|
+
- 示例:`std::atomic_store_explicit(&childrenList_, newList, std::memory_order_release)`
|
|
290
|
+
|
|
291
|
+
### thread_local最佳实践
|
|
292
|
+
|
|
293
|
+
thread_local 用于性能优化,避免多线程同步开销:
|
|
294
|
+
|
|
295
|
+
- **适用场景**:
|
|
296
|
+
- 线程独立的计数器/统计数据
|
|
297
|
+
- 线程独立的状态缓存
|
|
298
|
+
- 性能关键路径的临时数据
|
|
299
|
+
|
|
300
|
+
- **优势**:
|
|
301
|
+
- 每个线程独立存储,无需锁保护
|
|
302
|
+
- 访问速度与普通变量相同
|
|
303
|
+
- 自动管理生命周期
|
|
304
|
+
|
|
305
|
+
- **限制**:
|
|
306
|
+
- 不能用于需要跨线程共享的数据
|
|
307
|
+
- 注意线程销毁时的数据清理
|
|
308
|
+
|
|
309
|
+
### 全局变量分类处理
|
|
310
|
+
|
|
311
|
+
根据用途选择不同的保护策略:
|
|
312
|
+
|
|
313
|
+
- **统计计数器**:使用 `std::atomic` + `memory_order_relaxed`
|
|
314
|
+
- **缓存数据**:使用 `std::mutex` 保护或读写锁
|
|
315
|
+
- **配置数据**:使用 `std::call_once` 初始化,只读访问
|
|
316
|
+
- **线程独立数据**:使用 `thread_local`,无需同步
|
|
317
|
+
|
|
318
|
+
## 风险流分析(RiskFlow)
|
|
319
|
+
|
|
320
|
+
- **RISK_SOURCE**: 多线程环境下的共享数据访问
|
|
321
|
+
- **RISK_TYPE**: 数据竞争、竞态条件
|
|
322
|
+
- **RISK_PATH**: 共享数据 -> 无锁保护 -> 并发访问 -> 数据不一致/崩溃
|
|
323
|
+
- **IMPACT_POINT**: 数据损坏、程序崩溃、死锁、活锁
|
|
324
|
+
|
|
325
|
+
## 影响分析(ImpactAnalysis)
|
|
326
|
+
|
|
327
|
+
- **Trigger**: 多线程并发访问同一共享数据
|
|
328
|
+
- **Propagation**: 竞态条件导致数据不一致、内存错误
|
|
329
|
+
- **Consequence**: 数据损坏、程序崩溃、安全漏洞
|
|
330
|
+
- **Mitigation**: 使用mutex、atomic等同步机制保护共享数据
|
|
331
|
+
|
|
332
|
+
## 误报排除
|
|
333
|
+
|
|
334
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
335
|
+
|------|----------|----------|
|
|
336
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
337
|
+
| 已有锁保护 | 存在 lock_guard、unique_lock 等 | 不报 |
|
|
338
|
+
| 已使用 atomic | 变量类型为 std::atomic | 不报 |
|
|
339
|
+
| 线程局部存储 | thread_local 关键字 | 不报 |
|
|
340
|
+
| 只读数据 | constexpr、const 且无写入 | 不报 |
|
|
341
|
+
| 单线程场景 | 明确注释说明单线程 | 不报 |
|
|
342
|
+
## 测试用例
|
|
343
|
+
|
|
344
|
+
### 触发用例(应该报)
|
|
345
|
+
|
|
346
|
+
```cpp
|
|
347
|
+
// test_ConcurrencyStability_001_trigger.cpp
|
|
348
|
+
int g_counter = 0;
|
|
349
|
+
|
|
350
|
+
void trigger_bad_1()
|
|
351
|
+
{
|
|
352
|
+
g_counter++; // 应该报:全局变量无锁保护
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
class UnsafeQueue {
|
|
356
|
+
public:
|
|
357
|
+
void Push(int value) {
|
|
358
|
+
queue_.push_back(value); // 应该报:成员变量无锁保护
|
|
359
|
+
}
|
|
360
|
+
private:
|
|
361
|
+
std::deque<int> queue_;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
class Singleton {
|
|
365
|
+
public:
|
|
366
|
+
static Singleton* GetInstance() {
|
|
367
|
+
if (instance_ == nullptr) { // 应该报:单例模式竞态条件
|
|
368
|
+
instance_ = new Singleton();
|
|
369
|
+
}
|
|
370
|
+
return instance_;
|
|
371
|
+
}
|
|
372
|
+
private:
|
|
373
|
+
static Singleton* instance_;
|
|
374
|
+
};
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### 安全用例(不应该报)
|
|
378
|
+
|
|
379
|
+
```cpp
|
|
380
|
+
// test_ConcurrencyStability_001_safe.cpp
|
|
381
|
+
int g_counter = 0;
|
|
382
|
+
std::mutex g_mutex;
|
|
383
|
+
|
|
384
|
+
void safe_good_1()
|
|
385
|
+
{
|
|
386
|
+
std::lock_guard<std::mutex> lock(g_mutex);
|
|
387
|
+
g_counter++; // 安全:有锁保护
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
class SafeQueue {
|
|
391
|
+
public:
|
|
392
|
+
void Push(int value) {
|
|
393
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
394
|
+
queue_.push_back(value); // 安全:有锁保护
|
|
395
|
+
}
|
|
396
|
+
private:
|
|
397
|
+
std::deque<int> queue_;
|
|
398
|
+
std::mutex mutex_;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
std::atomic<int> g_atomicCounter(0);
|
|
402
|
+
|
|
403
|
+
void safe_good_2()
|
|
404
|
+
{
|
|
405
|
+
g_atomicCounter++; // 安全:使用atomic
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// NOPROTECT: 单线程场景
|
|
409
|
+
int g_singleThread = 0;
|
|
410
|
+
void noprotect_case()
|
|
411
|
+
{
|
|
412
|
+
g_singleThread++; // 不报:明确标记单线程
|
|
413
|
+
}
|
|
414
|
+
```
|