c++ 标准库多线程

news/2025/3/12 9:04:17/文章来源:https://www.cnblogs.com/edgarli/p/18766671

C++ 多线程编程允许程序同时执行多个任务,从而提高性能和响应能力。C++11 引入了 <thread> 库,使得多线程编程更加方便。以下是一些基本概念和示例,帮助你理解如何在 C++ 中进行多线程编程。

1. 创建线程

使用 std::thread 类可以创建一个新线程。你需要将一个函数或可调用对象传递给 std::thread 构造函数。

#include <iostream>
#include <thread>void threadFunction() {std::cout << "Hello from thread!\\\\n";
}int main() {std::thread t(threadFunction);  // 创建线程并执行 threadFunctiont.join();  // 等待线程结束std::cout << "Hello from main!\\\\n";return 0;
}

2. 传递参数给线程函数

你可以通过 std::thread 构造函数传递参数给线程函数。

#include <iostream>
#include <thread>void printMessage(const std::string& message) {std::cout << message << "\\\\n";
}int main() {std::thread t(printMessage, "Hello from thread!");t.join();std::cout << "Hello from main!\\\\n";return 0;
}

3. 线程同步

多个线程可能会同时访问共享资源,导致数据竞争。为了避免这种情况,可以使用互斥锁(std::mutex)来保护共享资源。

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx;  // 互斥锁void printNumber(int num) {mtx.lock();  // 加锁std::cout << "Number: " << num << "\\\\n";mtx.unlock();  // 解锁
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 10; ++i) {threads.emplace_back(printNumber, i);}for (auto& t : threads) {t.join();}return 0;
}

4. 使用 std::lock_guard 自动管理锁

std::lock_guard 是一个 RAII 风格的简单的锁管理器,它在构造时自动加锁,在析构时自动解锁。

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx;void printNumber(int num) {std::lock_guard<std::mutex> lock(mtx);  // 自动加锁和解锁std::cout << "Number: " << num << "\\\\n";
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 10; ++i) {threads.emplace_back(printNumber, i);}for (auto& t : threads) {t.join();}return 0;
}

5. 条件变量

条件变量(std::condition_variable)用于线程间的同步,允许一个线程等待另一个线程满足某些条件。

配合std::condition_variable::wait() 函数的第一个参数的必须是比lock_guard更灵活控制也更复杂重度的锁:std::unique_lock。它可以RAII自动析构,也可以手动lock/unlock,中间有的代码段就可以释放锁。手动把它unlock之后只是解锁,没有销毁,后续可以按需复用再次 lock/unlock。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void printMessage() {std::**unique_lock**<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; });  // 等待条件满足std::cout << "Hello from thread!\\\\n";
}int main() {std::thread t(printMessage);{std::lock_guard<std::mutex> lock(mtx);ready = true;  // 设置条件为 true}cv.notify_one();  // 通知等待的线程t.join();std::cout << "Hello from main!\\\\n";return 0;
}相比lock_guard的优势:
1. 灵活性:unique_lock 支持延迟锁定(可以先构造对象而不立即加锁),而 lock_guard 在构造时就必须加锁。这意味着你可以先创建 unique_lock 对象,然后根据程序逻辑需要时再调用 lock() 或 unlock() 方法进行手动加锁或解锁。
2. 条件变量的支持:unique_lock 可以与标准库中的条件变量一起使用,如 std::condition_variable,这是 lock_guard 所不具备的功能。这是因为条件变量需要能够原子地释放锁并进入等待状态,这正是 unique_lock 提供的能力之一。
3. 锁的所有权转移:unique_lock 支持移动语义(move semantics),允许将锁的所有权从一个 unique_lock 对象转移到另一个对象,从而使得锁可以在不同的作用域中传递。而 lock_guard 不支持这种操作,它的锁所有权是固定的。
4. 尝试锁定(try-locking):除了基本的 lock() 和 unlock() 方法外,unique_lock 还提供了 try_lock() 方法,该方法尝试获取锁但不会阻塞线程,如果无法获得锁则立即返回失败结果。这对于避免线程长时间阻塞非常有用。wait第二个参数predicate谓词的用法参见:
<https://en.cppreference.com/w/cpp/thread/condition_variable/wait>
predicate不满足不会结束等待执行后续语句。

6. 线程池

C++ 标准库没有直接提供线程池的实现,但你可以使用第三方库(如 Boost)或自己实现一个简单的线程池。

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>class ThreadPool {
public:ThreadPool(size_t numThreads) {for (size_t i = 0; i < numThreads; ++i) {workers.emplace_back([this] {while (true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(this->queueMutex);this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });if (this->stop && this->tasks.empty()) return;task = std::move(this->tasks.front());this->tasks.pop();}task();}});}}template<class F>void enqueue(F&& f) {{std::unique_lock<std::mutex> lock(queueMutex);tasks.emplace(std::forward<F>(f));}condition.notify_one();}~ThreadPool() {{std::unique_lock<std::mutex> lock(queueMutex);stop = true;}condition.notify_all();for (std::thread &worker : workers) {worker.join();}}private:std::vector<std::thread> workers;std::queue<std::function<void()>> tasks;std::mutex queueMutex;std::condition_variable condition;bool stop = false;
};int main() {ThreadPool pool(4);for (int i = 0; i < 8; ++i) {pool.enqueue([i] {std::cout << "Task " << i << " is running on thread " << std::this_thread::get_id() << "\\\\n";});}return 0;
}

7. 线程局部存储

线程局部存储(Thread Local Storage, TLS)允许每个线程拥有自己的变量实例。C++11 引入了 thread_local 关键字来实现这一点。

#include <iostream>
#include <thread>thread_local int threadLocalVar = 0;void threadFunction(int id) {threadLocalVar = id;std::cout << "Thread " << id << " has threadLocalVar = " << threadLocalVar << "\\\\n";
}int main() {std::thread t1(threadFunction, 1);std::thread t2(threadFunction, 2);t1.join();t2.join();return 0;
}

8. 异步任务

C++11 还引入了 std::asyncstd::future,用于异步执行任务并获取结果。

#include <iostream>
#include <future>int compute() {std::this_thread::sleep_for(std::chrono::seconds(2));return 42;
}int main() {// 启动异步任务std::future<int> fut = std::async(std::launch::async, compute);// 获取结果int result = fut.get();std::cout << "Result: " << result << std::endl;return 0;
}//使用 std::packaged_task (包在线程函数外)------------------------------------------
#include <iostream>
#include <future>
#include <thread>int compute() {std::this_thread::sleep_for(std::chrono::seconds(2));return 42;
}int main() {// 创建 packaged_task std::packaged_task<int()> task(compute);// 获取 futurestd::future<int> fut = task.get_future();// 在另一个线程中执行任务std::thread t(std::move(task));t.join();// 获取结果int result = fut.get();std::cout << "Result: " << result << std::endl;return 0;
}// 使用 std::promise (作为线程函数参数) -----------------------------------------------#include <iostream>
#include <future>
#include <thread>void compute(std::promise<int> prom) {std::this_thread::sleep_for(std::chrono::seconds(2));prom.set_value(42);
}int main() {// 创建 promise 和 futurestd::promise<int> prom;std::future<int> fut = prom.get_future();// 在另一个线程中执行任务std::thread t(compute, std::move(prom));// 获取结果int result = fut.get();std::cout << "Result: " << result << std::endl;t.join();return 0;
}

异步机制总结: C++11 的异步机制(std::future、std::async、std::packaged_task 和 std::promise)相比传统的多线程编程,提供了以下额外的好处:

更高的抽象层次,简化了异步操作的管理。
自动化的结果传递和异常处理。
更灵活的线程管理和任务执行策略。
更清晰的代码结构和更低的耦合度。
支持任务组合和超时等待。

这些机制使异步编程更加直观、安全和高效,是现代 C++ 并发编程的重要组成部分。

总结

C++ 多线程编程提供了强大的工具来处理并发任务。通过使用 std::threadstd::mutexstd::condition_variable 等工具,你可以编写高效且安全的多线程程序。需要注意的是,多线程编程容易引入数据竞争和死锁等问题,因此需要仔细设计和测试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/897546.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025-03-12 随笔

今天周三,天气不错,记

线上测试木舟物联网平台之如何通过HTTP网络组件接入设备

一、概述 木舟 (Kayak) 是什么?木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还…

经过 10 亿级性能验证的隐私计算开源利器

在数据驱动的时代,我们每天都在产生大量数据:购物记录、健康信息、社交关系……这些数据蕴含巨大价值,但也伴随着隐私泄露的风险。 试想一下:医院希望联合研究某种疾病,但患者数据无法直接共享。 银行想合作分析反欺诈信息,但客户隐私数据必须严格保护。 AI 公司需要使用…

值得推荐的IT公司名单(国企篇)

大家好,今天我们来盘点一下值得推荐的国企,这些企业在行业内具有举足轻重的地位,不仅主营业务突出,福利待遇优厚,尤其是研发岗位的薪资区间,更是让人眼前一亮。十大顶尖央企国企,待遇优厚如天花板级别!(排名不分先后)1、中国烟草总公司 人家都说能成为烟草总公司的一…

Entity Framework Core 数据库迁移

EF Core 通过两种方式来保持**模型**和**数据库架构**同步。 迁移 Code First 反向工程 Db First 管理迁移 通过EF Core 命令行工具来管理迁移 安装EF Core 命令行工具# 安装 dotnet-ef dotnet tool install --global dotnet-ef# 验证安装 dotnet ef# 更新工具 dotnet tool upd…

Roslyn 分析器已知问题 传递项目属性时将忽略分号之后的内容

本文记录 Roslyn 分析器、源代码生成器的已知问题,通过CompilerVisibleProperty 传递值时,所有在 `;`、`#` 和换行符之后的字符都会被忽略相关问题链接:https://github.com/dotnet/roslyn/issues/43970 https://github.com/dotnet/roslyn/issues/51692此问题由 walterlv 发现…

Avalonia 已知问题 继承滚动条将让里层控件无法获得无穷大空间

本文记录 Avalonia 的一个已知问题,如果有代码里面编写一个类型继承 ScrollViewer 类型,然后这个类型里面啥都不做。那将会导致所有放在此滚动条里面的控件无法获取无穷大的空间,其宽高无法撑开,被限定为上层容器尺寸复现步骤如下:新建一个 FooScrollViewer 类型,让其继承…

读DAMA数据管理知识体系指南17数据存储和操作治理

读DAMA数据管理知识体系指南17数据存储和操作治理1. 管理数据库性能 1.1. 数据库的性能取决于两个相互依赖的因素:可用性和响应速度 1.2. 性能包括确保空间的可用性、查询优化以及其他能使数据库以有效的方式返回数据的因素1.2.1. 如果没有可用性,就无法衡量数据库的性能1.2.…

干货分享!厦大140页PPT读懂大模型,从概念到实践

干货分享!厦大140页PPT读懂大模型 《厦门大学:大模型概念、技术与应用实践》 是由厦门大学大数据教学团队出品的DeepSeek科普类内容。文章涵盖:人工智能发展简史 人工智能思维 大模型:人工智能的前沿 AIGC应用与实践内容分享:引言 在数字化浪潮汹涌澎湃的当下,大模型如同…

一款基于.NET开源、强大的网络管理和网络问题排查工具!

前言 今天大姚给大家分享一款基于.NET开源、免费、功能强大的网络管理和网络问题排查工具:NETworkManager。 项目介绍 NETworkManager 是一个基于.NET开源(GPL-3.0 license)、免费、功能强大的开源工具,旨在帮助用户管理和解决网络问题。通过提供一系列网络连接和管理工具,…

Palera1n之苹果手机越狱,iOS15~iOS 18有根越狱方法

iOS15/16/17/18越狱教程用到的工具为palra1n ,该工具支持使用Sileo商店并安装插件。其他越狱方式可参考:https://www.cnblogs.com/codtina/可以添加对其他 arm64 Darwin 设备的支持,包括 Apple TV、HomePod 和 Darwin 21 及更高版本上的 iBridge,但目前不受支持。 永远不会支…