跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

C++如何安全地进行线程间数据共享?(代码示例)

C++线程安全共享数据需避免数据竞争,主要用std::mutex保护复合操作、std::atomic处理单变量读写、shared_ptr管理生命周期,并慎用全局/静态变量。 在C++中安全地进行线程间数据共享,核心是避免数据竞争(data race),即多个线程同时访问同一内存位置,且至少有一个是写操作,又无 同步机制 。关键手段是使用互斥量(
std::mutex
)、原子操作(
std::atomic
)或无锁编程技巧,配合恰当的生命周期管理。 用 std::mutex 保护共享变量 适用于需要保护一段复杂逻辑(如读-改-写)的场景。注意:互斥量本身不能被拷贝,需通过引用或指针传递;锁的粒度要合理——太粗影响并发性,太细则易出错或死锁。 示例:两个线程对同一计数器做自增
#include #include #include int counter = 0; std::mutex mtx; void increment() { for (int i = 0; i < 100000; ++i) { std::lock_guard lock(mtx); // RAII 自动加锁/解锁 ++counter; } } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Final counter: " << counter << "\n"; // 输出 200000 }
用 std::atomic 替代简单读写 适用于单个变量的读、写、自增等基础操作。原子类型提供无锁、线程安全的语义,性能通常优于互斥量,但不适用于复合操作(如“先读再条件更新”需
compare_exchange_weak
)。 立即学习 “ C++免费学习笔记(深入) ”; 多线程技术在iOS开发中的使用 WORD版 本文档主要讲述的是多线程技术在iOS开发中的使用;所谓进程对应的是一个应用程序,负责开辟内存空间供应用程序使用,但是进程不能执行任务(指令)。一个进程至少包含一条线程,线程是程序的执行流。 iOS程序启动时,在创建一个进程的同时, 会开始运行一个线程,该线程被称为主线程;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载 示例:用
std::atomic_int
实现线程安全计数器
#include #include #include std::atomic_int counter{0}; void increment_atomic() { for (int i = 0; i < 100000; ++i) { counter.fetch_add(1, std::memory_order_relaxed); } } int main() { std::thread t1(increment_atomic); std::thread t2(increment_atomic); t1.join(); t2.join(); std::cout << "Final counter: " << counter.load() << "\n"; }
避免悬挂指针:确保共享数据生命周期足够长 常见错误是在线程中访问局部变量地址,或提前释放堆内存。推荐方式包括:将数据作为对象成员、使用
std::shared_ptr
管理所有权、或明确约定生命周期由主线程负责。 不要把局部变量地址传给线程(栈内存会销毁) 若共享动态分配对象,用
std::shared_ptr
保证其存活到所有线程结束 可借助
std::jthread
(C++20)自动 join,减少资源管理疏漏 慎用全局变量和静态变量 它们天然跨线程可见,但极易引发隐式共享和初始化顺序问题。C++11 起,带构造函数的静态局部变量是线程安全初始化的(一次且仅一次),但之后的访问仍需同步。 例如以下代码是安全的初始化,但后续修改仍需保护:
std::map& get_cache() { static std::map cache; // 初始化线程安全 return cache; } // 使用时: { auto& c = get_cache(); std::lock_guard lock(cache_mutex); c[42] = "hello"; // 修改仍需加锁! }

相关文章