文章目录
1、std::future的其他成员函数
1.1 std::future_status
-
枚举类,用来表示
future
的返回状态// ENUM future_status enum class future_status { // names for timed wait function returns ready, timeout, deferred };
1.2 wait_for()
future
成员函数,返回值为future_status
- 作用:等待时间
1.3 示例代码
#include <iostream>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
//线程入口函数
int mythread()
{
//打印新线程id值
cout << "mythread() start " << "threadid = " << std::this_thread::get_id() << endl;
std::chrono::milliseconds dura(5000); //休息5s
std::this_thread::sleep_for(dura);
cout << "mythread() end " << "threadid = " << std::this_thread::get_id() << endl;
return 5;
}
int main()
{
cout << "main " << "threadid = " << std::this_thread::get_id() << endl;
//创建一个线程并开始执行,将future对象和async创建的线程绑定到了一起,流程不卡到这里
std::future<int> result = std::async(mythread);
//std::future<int> result = std::async(std::launch::deferred,mythread);
cout << "continue......!" << endl;
//std::future_status status = result.wait_for(std::chrono::seconds(1)); //等待1s
std::future_status status = result.wait_for(std::chrono::seconds(6)); //等待6s
if (status == std::future_status::timeout)
{
//超时:表示线程还没执行完;
cout << "超时,线程还没有执行完毕" << endl;
}
else if (status == std::future_status::ready)
{
//表示线程成功返回
cout << "线程成功执行完毕,返回" << endl;
cout << result.get() << endl;
}
else if (status == std::future_status::deferred) //延迟
{
//如果async的第一个参数被设置为std::launch::deferred,则本条件成立
cout << "线程被延迟执行" << endl; //实际上没有创建子线程,用了deferred就是在主线程中执行
cout << result.get() << endl;
}
cout << "I love China!" << endl;
return 0;
}
2、std::shared_future
- 类模板,
get()
函数复制数据
2.1 get_future()
- 获取线程返回的结果,和
std::future::get()
一样。
2.2 share()
- 和
std::move()
一样,对future
对象进行移动语义,移动过后,原future
对象不再含有值,新future
对象含有该值。
2.3 valid()
- 判断
future
对象是否含有有效值,有则返回true
,没有,则返回false
。
2.4 示例代码:
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>
#include <future>
using namespace std;
int mythread(int mypar) //注意第一个参数写法
{
cout << "mythread()id = " << std::this_thread::get_id() << endl;
//做其他运算,比如整整花费了5秒钟
std::chrono::milliseconds dura(5000);
std::this_thread::sleep_for(dura);
return 5;
}
void mythread2(std::shared_future<int>& tmpf)
{
cout << "mythread2() start " << " threadid = " << std::this_thread::get_id() << endl;
auto result = tmpf.get();
cout << "mythread2 result = " << result << endl;
return;
}
int main()
{
cout << "main " << "threadid = " << std::this_thread::get_id() << endl;
std::packaged_task<int(int)> mypt(mythread);
std::thread t1(std::ref(mypt), 1);
t1.join();
//获取结果值
//std::future<int> result = mypt.get_future();
//std::shared_future<int> result_s(std::move(result));
//bool ifcanget = result.valid();
//std::shared_future<int> result_s(result.share()); //执行完毕后result_s里有值,而result里空了
//ifcanget = result.valid();
std::shared_future<int> result_s(mypt.get_future()); //通过get_future返回值直接构造了一个shared_future对象
auto mythreadresult = result_s.get();
mythreadresult = result_s.get();
std::thread t2(mythread2, std::ref(result_s));
t2.join(); //等mythread2执行完毕
cout << "I love China!" << endl;
return 0;
}
3、原子操作std::atomic
3.1 原子操作概念引出范例
如下代码,两个线程同时对共享变量进行自加操作1000000次,理论结果应为2000000,而实际结果却不相符,代码如下:
#include <iostream>
#include <thread>
using namespace std;
int g_mycount = 0; //定义一个全局量
void mythread() //线程入口函数
{
for (int i = 0; i < 1000000; i++)
{
g_mycount++;
}
return;
}
int main()
{
thread mytobj1(mythread);
thread mytobj2(mythread);
mytobj1.join();
mytobj2.join();
cout << "两个线程执行完毕,最终g_mycount的结果是:" << g_mycount << endl;
cout << "I love China!" << endl;
return 0;
}
结果如下:
结果说明,这种两个线程同时干一件事情是极可能不稳定的,所以需要用到互斥量或者原子操作。
概念
- 可以把原子操作理解成一种:不需要用到互斥量加锁,也就是无锁技术的多线程并发编程方式。
- 原子操作:是在多线程中不会被打断的程序执行片段。
- 原子操作比互斥量效率上更胜一筹。
- 互斥量的加锁一般是针对一个代码段,而原子操作针对的一般都是一个变量,而不是一个代码段。
- 原子操作,一般都是指“不可分割的操作”,也就是说这种操作状态要么时完成的,要么是没完成的,不可能出现半完成状态。
std::atomic
来代表原子操作。- 类模板,用来封装某个类型的值的。
//我们封装了一个类型为int的对象(值),具有原子操作性质,我们可以像操作一个int类型变量一样来操作这个g_mycount
std::atomic<int> g_mycount = 0;
3.2 基本的std::atomic用法范例
示例代码1,对int类型进行操作:
#include <iostream>
#include <thread>
#include <future>
using namespace std;
//我们封装了一个类型为int的对象(值),具有原子操作性质,我们可以像操作一个int类型变量一样来操作这个g_mycount
std::atomic<int> g_mycount = 0;
void mythread() //线程入口函数
{
for (int i = 0; i < 1000000; i++)
{
g_mycount++; //对应的操作室原子操作,不会被打断
}
return;
}
int main()
{
thread mytobj1(mythread);
thread mytobj2(mythread);
mytobj1.join();
mytobj2.join();
cout << "两个线程执行完毕,最终g_mycount的结果是:" << g_mycount << endl;
cout << "I love China!" << endl;
return 0;
}
示例代码2,对bool类型进行操作:
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>
#include <future>
using namespace std;
std::atomic<bool> g_ifend = false; //线程退出标记,这里是原子操作,防止读和写乱套
void mythread()
{
std::chrono::milliseconds dura(1000); //1s
while (g_ifend == false)
{
//系统没要求线程退出,所以本线程可以干自己想干的事请
cout << "thread id = " << std::this_thread::get_id() << "运行中......" << endl;
std::this_thread::sleep_for(dura);
}
cout << "thread id = " << std::this_thread::get_id() << "运行结束......" << endl;
return;
}
int main()
{
thread mytobj1(mythread);
thread mytobj2(mythread);
std::chrono::milliseconds dura1(5000);
std::this_thread::sleep_for(dura1);
g_ifend = true; //对原子对象的写操作,让线程自行运行结束;
mytobj1.join();
mytobj2.join();
cout << "程序执行完毕,退出!" << endl;
return 0;
}
注:本人学习c++多线程视频地址:C++多线程学习地址