
(C++11/14/17学习笔记):std::atomic续、std::async与std::thread对比
发布日期:2021-05-07 15:19:55
浏览次数:11
分类:精选文章
本文共 3269 字,大约阅读时间需要 10 分钟。
std::atomic续谈与std::async与std::thread对比
原子操作std::atomic续谈
在多线程编程中,原子操作是保证在多个线程之间保持一致性和正确性的关键。C++中的std::atomic提供了一种轻量级的原子操作机制,适用于处理不可线性化的变量操作。以下是关于std::atomic的一些关键点:
原子操作的支持操作:
std::atomic支持以下操作:++
、--
、+=
、=
、|=
和^=
。这些操作在多线程环境下保证原子性,防止数据竞争和舍去。例如,my_count += 1
会比my_count = my_count + 1
更安全,因为前者不会在操作过程中被打断。原子操作的实现方式:
可以通过std::atomic<int>
类来封装整数类型的变量,像操作普通变量一样使用。例如:#include
#include #include int my_count{ 0 }; // 使用std::atomic 封装int变量void my_thread() { for (int i = 0; i < 1000000; ++i) { my_count += 1; // 原子操作,保证线程安全 }}int main() { std::thread threadObj1(my_thread); std::thread threadObj2(my_thread); threadObj1.join(); threadObj2.join(); std::cout << "两个线程执行完毕,最终 my_count的值是" << my_count << std::endl; return 0;} 通过上述代码可以看到,多个线程同时对my_count进行操作时,结果仍然是正确的。
注意事项:
如果使用my_count = my_count + 1
,则不一定保证原子性,因为在某些情况下可能会导致不可见的读写冲突。因此,建议在多线程环境下始终使用支持的原子操作符。
std::async与std::thread的区别
std::async和std::thread都是用于在C++中创建和管理线程的工具,但它们在工作机制和使用方式上有显著的不同。以下是详细对比:
1. std::async的参数和作用
std::async接受一个入口函数作为参数,可以通过以下方式使用:
#include#include #include using namespace std;future result = async(mythread);// 或者future result = async(std::launch::async, mythread);
参数说明:
std::launch::deferred
:延迟调用,异步任务不会立即执行。std::launch::async
:强制在新线程上执行异步任务。- 默认参数:
std::launch::async | std::launch::deferred
,系统会自行选择策略。
作用:
std::async创建的是一个异步任务,而不是直接创建线程。任务的执行方式取决于系统的资源情况:- 如果资源充足,系统可能选择在新线程上执行。
- 如果资源紧张,系统可能选择延迟执行任务。
2. std::thread的特点
- 资源消耗:std::thread会直接创建新线程。如果系统资源紧张,可能会抛出异常,导致程序崩溃。
- 线程管理:创建线程后,必须调用
join()
来等待线程完成,否则可能导致资源泄漏。 - 返回值:线程函数返回值不易获取,通常需要通过共享变量的方式传递。
3. std::async的灵活性
- 资源管理:如果系统资源紧张,std::async不会强制创建线程,而是将任务推迟到future的
get()
或wait()
方法调用时执行。 - 线程调度:异步任务可以在等待future结果的线程上自动执行,这避免了不必要的线程切换开销。
4. 资源限制的影响
- std::thread:线程数量过多可能导致系统资源耗尽,甚至崩溃。
- std::async:如果系统资源紧张,异步任务可能不会立即创建线程,而是等待future的调用执行。这种方式在资源受限的情况下更可靠。
std::async的不确定性问题
在使用std::async时,可能会遇到不确定性问题。例如,系统可能选择使用std::launch::deferred
(延迟调用)或std::launch::async
(立即创建新线程)。要解决这种不确定性,可以通过以下方式判断任务执行情况:
示例代码
#include#include #include #include using namespace std;int mythread() { cout << "mythread start" << "ThreadId = " << this_thread::get_id() << endl; cout << "mythread end" << "ThreadId = " << this_thread::get_id() << endl; return 100;}int main() { cout << "MainThreadID = " << this_thread::get_id() << endl; future result = async(mythread); future_status status = result.wait_for(0s); // 等待0秒判断状态 if (status == future_status::deferred) { cout << result.get() << endl; } else if (status == future_status::ready) { cout << "线程成功执行完毕并返回!" << endl; cout << result.get() << endl; } else if (status == future_status::timeout) { cout << "超时线程没执行完!" << endl; cout << result.get() << endl; } return 0;}
通过result.wait_for(0s)
,可以判断异步任务的执行方式:
- future_status::deferred:任务被延迟执行。
- future_status::ready:任务已经完成。
- future_status::timeout:任务未完成,但超时。
总结
std::async与std::thread在多线程编程中的应用场景有显著不同。std::async更注重灵活性和资源管理,适合在资源有限的情况下使用。通过合理配置launch策略和检查future状态,可以有效应对异步任务的不确定性问题。在实际开发中,应根据具体需求选择适合的线程创建方式,同时注意资源管理和状态判断,以确保程序的稳定性和性能。
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年04月11日 03时01分09秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Github上量化交易相关项目汇总
2021-05-07
JS取出两个数组中的不同或相同元素
2021-05-07
Ubuntu 18.04 zip压缩文件及其文件 夹中的所以 内容
2021-05-07
MFC:pic控件的矩形的left、right、top、bottom 坐标位置
2021-05-07
int 转 CString
2021-05-07
Edit编辑框自动换行与长度
2021-05-07
如何在Windows上搭建NFS服务器实现开发板与Windows之间的文件共享
2021-05-07
英语02_单词词性
2021-05-07
C语言08_数组[ Array ]
2021-05-07
C语言12_预处理 #
2021-05-07
低通滤波器的设计
2021-05-07
窄带随机过程的产生
2021-05-07
随机四则运算
2021-05-07
Maven
2021-05-07
zookeeper使用
2021-05-07
Java入门常见错误总结
2021-05-07
Java重载overload
2021-05-07
Java面向对象
2021-05-07
JAVA带标签的break和continue
2021-05-07