一、future 扩展
1、future 的其他成员函数
class MyClass { public: int MyThread(int param); // 假定一个线程函数是有返回值的 }; int main() { MyClass ele; std::future<int> result = std::async(&MyClass::MyThread, &ele, 5); std::future_status status = result.wait_for(std::chrono::seconds(2)); // 此时等待2秒。 返回示 result 绑定的线程执行了2秒之后,目前的状态 if (status == std::future_status::timeout) { // 超时:表示线程还是没有执行完,即线程执行的时间超过2秒 // 最终在主线程return 0 之前,会等待线程执行完 } else if (status == std::future_status::ready) { // 表示线程成功返回 // 此时可以得到线程执行后的结果 } else if (status == std::future_status::deferred) { // 表示线程会被延迟创建,如果没有调用future.get() 函数,线程不会被创建 // 与第一个参数 std::async() 第一个参数为 std::launch::deferred 的情况相同, 与下句意思相同 // std::future<int> result = std::async(std::launch::deferred, &MyClass::MyThread, &ele, 5); result.get(); // 直到这句话才会执行 } system("pause"); return 0; }
2、shared_future
// future.get() 函数是一个移动语义,所以只能调用一次 future的get()函数,否则会编译报错 // 如果一个线程中的结果,要被其他多个线程使用,则需要用std::shared_future // std::shared_future 的 get() 函数是一个复制语义 std::future<int> result = std::async(&MyClass::MyThread, &ele, 5); std::shared_future<int> result_s(std::move(result)); // std::shared_future<int> result_s(result.share()); // 这两种方式都可以,都是移动语义 // 执行完毕后,result_s有值,result为空 bool isHaveValue = result.valid(); // 可以通过这个函数来判断是否有值 auto myValue = result_s.get(); // 这种写法是复制语义,可以执行多次
二、原子操作 std::atomic
1、概述
// 原子操作:可以理解成一种不需要用到互斥量技术的多线程并发变成方式 // 原子操作:是在多线程中不会被打断的程序执行片段 // 原子操作效率比互斥量效率上更好 // 互斥量加锁一般是一个代码段,原子操作一般针对的是一个变量 // 原子操作一般指“不可分割的操作”,操作状态要么是完成的,要么是未完成的,不会出现半完成状态
2、原子操作演示
int m_Int = 0; std::mutex m_mutex; std::atomic<int> m_automicInt = 0; // std::atomic 类模板,是用来封装某个类型的值 // 封装了一个类型为int的对象,我们可以像操作一个int类型变量一样操作该值 // 假设多个线程的入口函数都是这个函数, // 表示多个线程,都在改变m_int的值,则需要通过加锁技术来保证结果的正确性 void WriteIntValue() { for (int i = 0; i < 10000; ++i) { m_automicInt++; // 对应的操作是个原子操作,所以不会被打断 // 如果此处用的是普通的int 类型,则需要加锁来执行 //m_mutex.lock(); //m_Int++; //m_mutex.unlock(); m_automicInt += 1; // 结果正确 m_automicInt = m_automicInt + 1; // 结果错误:说明不是所有运算符都支持原子操作 // 原子操作一般支持: ++ -- += &= |= ^= 这些运算符,其他可能不支持 } }