| 中文 | English |
| 一、线程安全的概念 | 1. Concept of Thread Safety |
| 线程安全指在多线程环境中,多个线程访问同一资源时,不会导致竞态条件、数据破坏或未定义行为。 | Thread safety means that in a multithreaded environment, multiple threads accessing the same resource will not cause race conditions, data corruption, or undefined behavior. |
| 简单说,就是保证程序正确性和稳定性,即使多线程同时执行相关代码。 | In short, it guarantees program correctness and stability even when multiple threads execute related code simultaneously. |
| |
| 二、线程安全的级别 | 2. Levels of Thread Safety |
| 不安全(Not thread-safe):多线程同时访问会导致错误或竞态。 | Not thread-safe: concurrent access by multiple threads can cause errors or race conditions. |
| 线程安全(Thread-safe):多线程访问不会产生竞态,行为正确。 | Thread-safe: multiple threads can access safely without race conditions and behave correctly. |
| 可重入(Reentrant):函数可被多线程/中断安全调用,不依赖共享状态。 | Reentrant: functions can be safely called by multiple threads or interrupts, without relying on shared state. |
| 线程局部(Thread-local):每个线程拥有独立变量副本,互不干扰。 | Thread-local: each thread has its own copy of variables, avoiding interference. |
| |
| 三、C++中实现线程安全的常用方法 | 3. Common Ways to Achieve Thread Safety in C++ |
| 1. 互斥锁(Mutex):用std::mutex加锁,保证同一时刻只有一个线程访问共享资源。 | 1. Mutex: use std::mutex to lock and ensure only one thread accesses shared resource at a time. |
| 示例: | Example: |
| “`cpp | “`cpp |
| std::mutex mtx; | std::mutex mtx; |
| int shared_data = 0; | int shared_data = 0; |
| void safe_increment() { | void safe_increment() { |
| std::lock_guardstd::mutex lock(mtx); | std::lock_guardstd::mutex lock(mtx); |
| ++shared_data; | ++shared_data; |
| } | } |
| “` | “` |
| 2. 读写锁(Shared Mutex):允许多个线程读,写时独占锁,C++17 提供std::shared_mutex。 | 2. Shared Mutex: allows multiple readers concurrently but writer has exclusive lock, provided by C++17 as std::shared_mutex. |
| 3. 原子操作(Atomic):使用std::atomic实现无锁同步,适合简单类型变量。 | 3. Atomic: use std::atomic for lock-free synchronization, suitable for simple types. |
| 示例: | Example: |
| “`cpp | “`cpp |
| std::atomic<int> count(0); | std::atomic<int> count(0); |
| void increment() { | void increment() { |
| count.fetch_add(1, std::memory_order_relaxed); | count.fetch_add(1, std::memory_order_relaxed); |
| } | } |
| “` | “` |
| 4. 线程局部存储(Thread Local):用thread_local关键字为每线程分配独立变量。 | 4. Thread Local Storage: use thread_local keyword to assign each thread independent variables. |
| 5. 不可变数据/只读数据:共享只读数据天然线程安全。 | 5. Immutable / Read-only data: shared read-only data is naturally thread-safe. |
| |
| 四、线程安全的盲点与陷阱 | 4. Pitfalls and Common Problems in Thread Safety |
| 1. 竞态条件(Race Condition):多线程同时修改共享数据,导致不可预测结果。 | 1. Race Condition: concurrent modification causes unpredictable results. |
| 示例见下。 | See example below. |
| |
| 2. 死锁(Deadlock):多个线程互相等待对方持有的锁,导致程序卡死。 | 2. Deadlock: threads wait on each other’s locks causing indefinite blocking. |
| 示例见下。 | See example below. |
| |
| 3. 内存可见性(Memory Visibility):一个线程修改变量,另一个线程可能看不到最新值。 | 3. Memory Visibility: changes in one thread may not be visible to another thread immediately. |
| 示例见下。 | See example below. |
| |
| 4. 锁的粒度(Lock Granularity):锁范围过大导致性能瓶颈,过小则增加复杂度。 | 4. Lock Granularity: coarse locks cause performance bottlenecks; fine locks add complexity. |
| 示例见下。 | See example below. |
| |
| 5. 读写不一致(Read-Write Inconsistency):读写顺序未同步导致数据错误。 | 5. Read-Write Inconsistency: unsynchronized read/write order leads to incorrect data. |
| 示例见下。 | See example below. |
| |
| 五、盲点示例代码 | 5. Example Code for Pitfalls |
| |
| 竞态条件(Race Condition)示例: | Race Condition Example: |
| “`cpp | “`cpp |
| int counter = 0; | int counter = 0; |
| void unsafe_increment() { | void unsafe_increment() { |
| for(int i = 0; i < 1000; ++i) ++counter; | for(int i = 0; i < 1000; ++i) ++counter; |
| } | } |
| int main() { | int main() { |
| std::thread t1(unsafe_increment); | std::thread t1(unsafe_increment); |
| std::thread t2(unsafe_increment); | std::thread t2(unsafe_increment); |
| t1.join(); | t1.join(); |
| t2.join(); | t2.join(); |
| std::cout << “最终计数: ” << counter << std::endl; | std::cout << “Final count: ” << counter << std::endl; |
| return 0; | return 0; |
| } | } |
| “` | “` |
| |
| 死锁(Deadlock)示例: | Deadlock Example: |
| “`cpp | “`cpp |
| std::mutex mtx1, mtx2; | std::mutex mtx1, mtx2; |
| void threadA() { | void threadA() { |
| std::lock_guardstd::mutex lock1(mtx1); | std::lock_guardstd::mutex lock1(mtx1); |
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); | std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
| std::lock_guardstd::mutex lock2(mtx2); | std::lock_guardstd::mutex lock2(mtx2); |
| std::cout << “线程A完成\n”; | std::cout << “Thread A done\n”; |
| } | } |
| void threadB() { | void threadB() { |
| std::lock_guardstd::mutex lock2(mtx2); | std::lock_guardstd::mutex lock2(mtx2); |
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); | std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
| std::lock_guardstd::mutex lock1(mtx1); | std::lock_guardstd::mutex lock1(mtx1); |
| std::cout << “线程B完成\n”; | std::cout << “Thread B done\n”; |
| } | } |
| int main() { | int main() { |
| std::thread t1(threadA); | std::thread t1(threadA); |
| std::thread t2(threadB); | std::thread t2(threadB); |
| t1.join(); | t1.join(); |
| t2.join(); | t2.join(); |
| return 0; | return 0; |
| } | } |
| “` | “` |
| |
| 内存可见性(Memory Visibility)示例: | Memory Visibility Example: |
| “`cpp | “`cpp |
| bool ready = false; | bool ready = false; |
| int data = 0; | int data = 0; |
| void producer() { | void producer() { |
| data = 42; | data = 42; |
| ready = true; | ready = true; |
| } | } |
| void consumer() { | void consumer() { |
| while (!ready) { | while (!ready) { |
| std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |