future其他成员函数、share_future、atomic
一 std::future的其他成员函数
std::future_status
枚举类型,等待一定时间,查看线程是否执行完
枚举值:time_out ready deferred
#include <iostream>
#include <string>
#include <future>
#include <thread>
#include <mutex>
using namespace std;
int mythread()
{
cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
//sleep 5s
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread over"<<"thread_id:"<<std::this_thread::get_id<<endl;
return 5;
}
int main()
{
//一 future的其他成员函数
cout<<"main"<<"thread_id"<<std::this_thread::get_id<<endl;
//这里async的创建采用异步模式,即创建完就开始执行线程 std::launch::async
std::future<int> res = std::async(std::launch::async,mythread);
cout<<"continue.."<<endl;
// cout<<res.get()<<endl; //等待线程操作完成
std::future_status status = res.wait_for(std::chrono::seconds(1)); //等待一秒
if (status == std::future_status::timeout)
{
//超时,表示线程还没执行完
cout<<"time out"<<endl;
}
cout<<"ok"<<endl;
return 0;
}
主线程等待子线程执行完才结束
G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
mainthread_id1
continue..
mythread startthread_id:1
time out
ok
mythread overthread_id:1
Process finished with exit code 0
等待时间改为6s,再获取子线程的状态
#include <iostream>
#include <string>
#include <future>
#include <thread>
#include <mutex>
using namespace std;
int mythread()
{
cout<<"mythread start"<<"thread_id:"<<std::this_thread::get_id<<endl;
//sleep 5s
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
cout<<"mythread over"<<"thread_id:"<<std::this_thread::get_id<<endl;
return 5;
}
int main()
{
//一 future的其他成员函数
cout<<"main"<<"thread_id"<<std::this_thread::get_id<<endl;
std::future<int> res = std::async(std::launch::async,mythread);
cout<<"continue.."<<endl;
// cout<<res.get()<<endl; //等待线程操作完成
std::future_status status = res.wait_for(std::chrono::seconds(6)); //等待一秒
if (status == std::future_status::timeout)
{
//超时,表示线程还没执行完
cout<<"time out"<<endl;
}
else if(status == std::future_status::ready)
{
//超时,表示线程还没执行完
cout<<"thread success over"<<endl;
cout<<res.get()<<endl;
}
cout<<"ok"<<endl;
return 0;
}
6s过后,子线程已经执行完成了,status 为ready
G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
mainthread_id1
continue..
mythread startthread_id:1
mythread overthread_id:1
thread success over
5
ok
二 std::shared_future
类模板 与std::future不同的是,future对象使用get()获取到值并赋值给其他变量时,使用的是移动语义,数据被转移,赋值完成后,future对象内数据为空;而shared_future使用get()给其他变量赋值时,使用复制的方式,其内部的数据不会被转移。
cout<<"main"<<"thread_id"<<std::this_thread::get_id<<endl;
std::future<int> res = std::async(std::launch::async,mythread);
bool ifcanget = res.valid(); //判断res中是否有值
cout<<" res ifcanget = "<<ifcanget<<endl;
//将res的值移动到result中 res 空了 移动语义
std::shared_future<int>result (res.share());
ifcanget = res.valid();
cout<<" res ifcanget = "<<ifcanget<<endl;
auto myresult = result.get();
myresult = result.get();
myresult = result.get();
myresult = result.get();
cout<<"result if can get = "<<result.valid()<<endl;
cout<<"continue.."<<endl;
cout<<"ok"<<endl;
return 0;
G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
mainthread_id1
res ifcanget = 1
mythread startthread_id:1
res ifcanget = 0
mythread overthread_id:1
result if can get = 1
continue..
ok
Process finished with exit code 0
三 原子操作 std::atomic
3.1 原子操作概念引出范例
- 互斥量:多线程编程中,保护共享数据:锁,操作共享数据,开锁
- 两个线程,对一个变量进行操作,一个线程读,一个线程写
- 读线程,读取这个变量的数据
- 写线程,改变这个变量的值:一个赋值操作,可以分解成多个操作,所以如果执行多个操作中的其中一个步骤时,被读线程打断,则会读到不可预料的值。
int mycount = 0;
void writethread()
{
for (int i = 0; i < 1000; ++i)
{
mycount ++;
}
}
thread mytobj1(writethread);
thread mytobj2(writethread);
mytobj1.join();
mytobj2.join();
cout<<"two thread over,mycount = "<<mycount<<endl;
cout<<"ok"<<endl;
return 0;
结果打印:预期结果不是2000000
G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
two thread over,mycount = 1380024
ok
Process finished with exit code 0
使用互斥锁解决该问题
std::mutex my_mutex;
void writethread()
{
for (int i = 0; i < 1000; ++i)
{
my_mutex.lock();
mycount ++;
my_mutex.unlock();
}
}
2000000次加锁和解锁
结果打印
G:\C++Code\MultiThread\MultiThread2_10\cmake-build-debug\MultiThread2_10.exe
two thread over,mycount = 2000000
ok
Process finished with exit code 0
原子操作:
- 在多线程中不会被打断的程序执行片段,其效率比加锁和解锁更胜一筹。
- 互斥量的加锁一般针对一行或多行代码,原子操作一般针对一个变量,而不是一段代码段。
- 原子操作:可以理解为不可分割的操作。
- std::atomic代表原子操作,是个类模板,它是用来封装某个类型的值
- 将上述例子中的mycount封装成原子类型数据
//int mycount = 0;
std::atomic<int> mycount ;
3.2 基本的std::atomic用法范例
atomic对象的初始化:其初始化方式有多种,例如
std::atomic<int> mycount(0);
原子数据不需要互斥锁保护
void writethread()
{
for (int i = 0; i < 1000000; ++i)
{
mycount ++; //mycount为atomic对象,其操作不会被打断
}
}
thread mytobj1(writethread);
thread mytobj2(writethread);
mytobj1.join();
mytobj2.join();
cout<<"two thread over,mycount = "<<mycount<<endl;