C++线程安全函数

news/2024/12/28 0:15:03/

在 C++ 中,线程安全的函数是指在多线程环境下可以安全调用,不会导致数据竞争或其他并发问题的函数。C++ 标准库提供了许多线程安全的函数,同时也要求开发者在使用自定义函数时确保线程安全。以下是一些常见的线程安全函数和实现线程安全的方法:


1. 标准库中的线程安全函数

C++ 标准库中的许多函数是线程安全的,尤其是那些不涉及共享状态的函数。

1.1 <iostream> 中的线程安全函数

  • std::cout 和 std::cerr
    • 这些对象是线程安全的,但输出可能会交错。
    • 如果需要保证输出顺序,可以使用互斥锁保护。

1.2 <atomic> 中的线程安全函数

  • std::atomic<T>
    • 所有操作(如 load()store()fetch_add() 等)都是原子的。
    • 示例:
      std::atomic<int> counter(0);
      counter++;  // 线程安全
      

1.3 <thread> 中的线程安全函数

  • std::thread::join()
    • 等待线程完成,线程安全的。
  • std::thread::detach()
    • 分离线程,线程安全的。

1.4 <mutex> 中的线程安全函数

  • std::mutex::lock() 和 std::mutex::unlock()
    • 用于保护共享资源,线程安全的。
  • std::lock_guard 和 std::unique_lock
    • 自动管理锁的生命周期,线程安全的。

1.5 <condition_variable> 中的线程安全函数

  • std::condition_variable::wait()
    • 等待条件变量,线程安全的。
  • std::condition_variable::notify_one() 和 notify_all()
    • 通知等待的线程,线程安全的。

1.6 <future> 中的线程安全函数

  • std::future::get()
    • 获取异步操作的结果,线程安全的。
  • std::promise::set_value()
    • 设置异步操作的结果,线程安全的。

1.7 <chrono> 中的线程安全函数

  • std::chrono::system_clock::now()
    • 获取当前时间,线程安全的。

2. 自定义线程安全函数

如果需要编写自定义的线程安全函数,可以通过以下方式实现:

2.1 使用互斥锁(std::mutex

通过互斥锁保护共享资源,确保线程安全。

示例:

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;
int shared_data = 0;void threadSafeFunction() {std::lock_guard<std::mutex> lock(mtx);  // 自动加锁和解锁shared_data++;std::cout << "Shared data: " << shared_data << std::endl;
}int main() {std::thread t1(threadSafeFunction);std::thread t2(threadSafeFunction);t1.join();t2.join();return 0;
}

2.2 使用原子操作(std::atomic

对于简单的数据类型,可以使用原子操作避免数据竞争。

示例:

#include <iostream>
#include <thread>
#include <atomic>std::atomic<int> shared_data(0);void threadSafeFunction() {shared_data++;  // 原子操作std::cout << "Shared data: " << shared_data.load() << std::endl;
}int main() {std::thread t1(threadSafeFunction);std::thread t2(threadSafeFunction);t1.join();t2.join();return 0;
}

2.3 使用条件变量(std::condition_variable

通过条件变量实现线程间的同步。

示例:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void threadSafeFunction() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [] { return ready; });  // 等待条件变量std::cout << "Thread is running." << std::endl;
}int main() {std::thread t(threadSafeFunction);{std::lock_guard<std::mutex> lock(mtx);ready = true;  // 修改条件}cv.notify_one();  // 通知等待的线程t.join();return 0;
}

3. 线程安全的容器

C++ 标准库提供了一些线程安全的容器,但需要注意的是,标准库容器本身并不是线程安全的,需要手动加锁保护。

3.1 线程安全的容器示例

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx;
std::vector<int> shared_vector;void threadSafeFunction(int value) {std::lock_guard<std::mutex> lock(mtx);  // 加锁保护shared_vector.push_back(value);
}int main() {std::thread t1(threadSafeFunction, 1);std::thread t2(threadSafeFunction, 2);t1.join();t2.join();for (int v : shared_vector) {std::cout << v << " ";}return 0;
}

4. 线程安全的单例模式

单例模式是一种常见的设计模式,可以通过双重检查锁定(Double-Checked Locking)实现线程安全的单例。

示例:

#include <iostream>
#include <mutex>
#include <memory>class Singleton {
public:static Singleton& getInstance() {static std::once_flag flag;std::call_once(flag, [] { instance.reset(new Singleton); });return *instance;}private:Singleton() = default;static std::unique_ptr<Singleton> instance;
};std::unique_ptr<Singleton> Singleton::instance;int main() {Singleton& s1 = Singleton::getInstance();Singleton& s2 = Singleton::getInstance();std::cout << &s1 << " " << &s2 << std::endl;  // 地址相同return 0;
}

总结

C++ 提供了丰富的工具来实现线程安全:

  1. 标准库函数:如 std::coutstd::atomicstd::mutex 等。
  2. 互斥锁:通过 std::mutex 保护共享资源。
  3. 原子操作:使用 std::atomic 避免数据竞争。
  4. 条件变量:通过 std::condition_variable 实现线程同步。
  5. 线程安全容器:手动加锁保护标准库容器。
  6. 单例模式:使用双重检查锁定或 std::call_once 实现线程安全的单例。

根据具体需求选择合适的方式,可以实现高效、安全的并发编程。

 


http://www.ppmy.cn/news/1558644.html

相关文章

AIDD - 人工智能药物设计 - 在 Docker 上创建和运行 PostgreSQL + RDKit 卡带环境

在 Docker 上创建和运行 PostgreSQL RDKit 卡带环境 背景 我们将讨论化学数据库。 看起来&#xff0c;如果你在 PostgreSQL 中放置一个 RDKit cartridge &#xff08;扩展&#xff09;&#xff0c;就可以基于 SQL 进行结构相似性搜索&#xff0c;看起来很有趣。但是我找不到…

Go的初级核心实用开发

Go 语言因其简洁、高效和强大的并发支持而广受欢迎&#xff0c;尤其适合构建网络服务、分布式系统和高性能应用。以下是 Go 编程中的一些实用技巧&#xff0c;帮助你编写更高效、更简洁且易于维护的代码。 1. 使用 defer 简化资源管理 defer 是 Go 中非常有用的特性&#xff…

寻找适合小户型的开源知识库open source knowledge base之路

寻找一个开源的知识库&#xff0c;为了把以前花很多时间收集的信息或是项目/课程资料放到一个容易归类和管理的私有自主系统中&#xff0c;以便更容易查阅&#xff0c;花更少时间收集、对比版本及分享等一系列管理工作&#xff0c;同时确保在需要时可以相对快速找到有用的资料&…

易语言 OCR 文字识别

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

Vivado 编译(单核性能对比+高性能迷你主机+Ubuntu20.04/22.04安装与区别+20.04使用远程命令)

目录 1. 简介 2. 单核性能对比 2.1 PassMark 2.2 geekbench 2.3 CPU-7 2.4 选择 UM790 pro 3. Ubuntu 22.04 物理机 3.1 安装 Ubuntu 22.04 3.2 安装 Vitis 2022.1 3.3 缺点 4. Ubuntu 20.04 物理机 4.1 安装 Ubuntu 20.04 4.2 实用命令 4.2.1 SSH 保持活跃 4.2…

docker部署微信小程序自动构建发布和更新

通过 Jenkins 和 Docker 部署微信小程序&#xff0c;并实现自动构建、发布和版本更新&#xff0c;主要涉及以下几个步骤&#xff1a; 设置 Jenkins 环境配置 GitLab 与 Jenkins 的集成构建 Docker 镜像部署和发布微信小程序配置 Jenkins 自动构建 以下是详细的步骤说明&#…

redis与aerospike性能及数据结构对比与分析

Redis 和 Aerospike 都是高性能的 NoSQL 数据库&#xff0c;但它们在性能、数据结构和使用场景上有显著差异。以下是对两者的性能和数据结构进行详细对比与分析。 1. 性能对比 Redis 性能&#xff1a; 内存存储&#xff1a; Redis 将所有数据存储在内存中&#xff0c;因此读写…

鸿蒙之路的坑

1、系统 Windows 10 家庭版不可用模拟器 对应的解决方案【坑】 升级系统版本 直接更改密钥可自动升级系统 密钥找对应系统的&#xff08;例&#xff1a;windows 10专业版&#xff09; 升级完之后要激活 坑1、升级完后事先创建好的模拟器还是无法启动 解决&#xff1a;删除模拟…