C++ 多线程笔记3
std::future其他的成员函数wait_for()
wait_for()
返回的是一个枚举类型 std::future_status
std::future_status
是枚举类型,表示异步任务的执行状态。类型的取值有
std::future_status::timeout
: 表示线程还没执行完std::future_status::ready
:表示线程在规定时间内完成std::future_status::deferred
: 表示std::async()
使用了std::launch::deferred
wait_for()
用于卡住当前流程,等待 std::async()
的异步任务运行一段时间,然后返回其状态 std::future_status
。如果 std::async()
的参数是 std::launch::deferred
(延迟执行),则不会卡住主流程。
1 | // std::future<int> result = std::async(std::launch::deferred, mythread); |
我么也可以通过 wait_for()
来判断系统通过 std::async(mythread)
创建的异步任务是否创建了线程
如果进入 else if(status == std::future_status::deferred)
则表示系统资源紧张而直接在主线程中调用了线程入口函数 mythread()
std::shard_future类模板
std::future
与 std::shared_future
不同
std::future
的get()
成员函数是转移数据,也就是说采用了移动语义我们可以使用
result
中的valid()
函数来判断是否还有值1
2
3
4
5std::future<int> result = std::async([]{
return 4;
});
result.get();
bool isget = result.valid();isget == false
则说明result
没有值std::shared_future
的get()
成员函数是复制数据
std::atomic原子操作
原子操作概念引出范例
两个线程同时进行加法运算,导致最后结果不准确,因为线程的不断切换中会打断代码导致没运行完整
通过互斥量来进行加锁解锁才会让加法计算运行准确
原子操作可以理解为:不需要用到互斥量加锁(无锁)技术的多线程并发编程方式
也就是说:是在多线程中 不会被打断的程序执行片段,原子操作,效率上比互斥量更胜一筹
互斥量的加锁一般是针对一个代码段(多行代码),二原子操作针对的一般都是一个变量,而不是一个代码段
1 | int g_i = 0; // 定义一个全局变量 |
按理来说 g_i
应该为 200000 ,但因为线程的切换导致不会加到 200000,且每次结果都不会相同
std::atomic
std::atomic 是一个类模板,用于封装某个类型的值,有两种初始化方式
1 | std::atomic<int> a = {0}; // 初始化 |
原子操作,一般都是指“不可分割的操作”;也就是说这种操作状态要么是完成的,要么是没完成的,不可能出现半完成状态
一般atomic原子操作,针对++,--,+=,-=,&=,|=,^=
是支持的,其他操作不一定支持。
补充
1 | std::atomic<int> atm = 0; |
这里只有读取 atm
是原子操作,但是整个这一行代码 cout << atm << endl;
并不是原子操作,导致最终显示在屏幕上的值是一个“曾经值”。
1 | std::atomic<int> atm = 0; |
这种拷贝初始化不可以,会报错。
1 | atomic<int> atm2(atm.load()); |
load()
:以原子方式读 atomic
对象的值。
1 | atm2.store(12); |
store()
:以原子方式写入内容
原子操作实质上是:不允许在进行原子对象操作时进行CPU的上下文切换。