一:std::future的其他成员函数
future_status中ready、timeout、deferred三种枚举状态。
int mythread() //线程入口函数
{
cout << "mythread() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
}
int main()
{
cout << "main threadId = " << std::this_thread::get_id() << endl;
//std::future<int> result = std::async(mythread);
std::future<int> result = std::async(std::launch::deferred, mythread);
cout << "continue...!" << endl;
//cout << result.get() << endl; //卡在这个等待线程执行完。
//但是这种get因为一些内部特殊操作,不能get多次,智能get一次。
//枚举类型:
//wait_for(等待一定的时间);
std::future_status status = result.wait_for(std::chrono::seconds(6)); //等待一秒
if (status == std::future_status::timeout) //超时:等待子线程一秒钟,希望其返回,如果没有返回,那么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::future<int> result = std::async(std::launch::deferred, mythread); 则本条件成立
cout << "线程被延迟执行" << endl;
cout << result.get() << endl; //在主线程中被执行
}
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
二:std::shared_future
std::shared_future也是个类模板,get()函数是复制数据
int mythread1(int mypar) //线程入口函数
{
cout << mypar << endl;
cout << "mythread1() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(5000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread1() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
}
void mythread2(std::future<int>& tmpf) //注意参数
//void mythread2(std::shared_future<int>& tmpf)
{
cout << "mythread2() start " << "threadid = " << std::this_thread::get_id() << endl;
auto result = tmpf.get(); //获取值,只能get一次否则会报异常。
//auto result = tmpf.get(); //为什么第二次get这个future会得到异常;主要是因为get函数的设计,是一个移动语义
cout << "mythread2 result = " << result << endl;
return;
}
int main()
{
//std::future的其他成员函数,get()函数式转移数据
cout << "main threadId = " << std::this_thread::get_id() << endl;
//packaged_task<int(int)> 第一个int是函数返回类型,第二个是参数类型
std::packaged_task<int(int)> mypt(mythread1); //把函数mythread通过packaged_task包装起来
std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第二个参数作为线程入口函数的参数。
t1.join(); //可以调用这个等待线程执行完毕,不调用这个不太行,会崩溃。
std::future<int> result = mypt.get_future();
std::thread t2(mythread2, std::ref(result));
t2.join(); //等线程执行完毕
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
std::shared_future,get()函数是复制数据。
std::future的其他成员函数,get()函数是转移数据。
int mythread1(int mypar) //线程入口函数
{
cout << mypar << endl;
cout << "mythread1() start" << " threadId = " << std::this_thread::get_id() << endl; //打印新线程id
std::chrono::milliseconds dura(2000); //定义一个5秒时间
std::this_thread::sleep_for(dura); //休息了一定时长
cout << "mythread1() end" << " threadId = " << std::this_thread::get_id() << endl;//打印新线程id
return 5;
}
//void mythread2(std::future<int>& tmpf) //注意参数
void mythread2(std::shared_future<int>& tmpf)
{
cout << "mythread2() start " << "threadid = " << std::this_thread::get_id() << endl;
auto result = tmpf.get(); //获取值,只能get一次否则会报异常。
//auto result = tmpf.get(); //为什么第二次get这个future会得到异常;主要是因为get函数的设计,是一个移动语义
cout << "mythread2 result = " << result << endl;
return;
}
int main()
{
//std::future的其他成员函数,get()函数式转移数据
cout << "main threadId = " << std::this_thread::get_id() << endl;
//packaged_task<int(int)> 第一个int是函数返回类型,第二个是参数类型
std::packaged_task<int(int)> mypt(mythread1); //把函数mythread通过packaged_task包装起来
std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第二个参数作为线程入口函数的参数。
t1.join(); //可以调用这个等待线程执行完毕,不调用这个不太行,会崩溃。
std::future<int> result = mypt.get_future();
bool ifcanget = result.valid();
//std::shared_future<int> result_s(std::move(result)); //必须用移动语义
std::shared_future<int> result_s(result.share()); //同上,执行完毕后result_s里有值,而result里空了
ifcanget = result.valid(); //值已经为空
auto mythread_result = result_s.get();
std::thread t2(mythread2, std::ref(result_s));
t2.join(); //等线程执行完毕
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
不使用std::future result = mypt.get_future();
替换成std::shared_future result_s(mypt.get_future());
int main()
{
//std::future的其他成员函数,get()函数式转移数据
cout << "main threadId = " << std::this_thread::get_id() << endl;
//packaged_task<int(int)> 第一个int是函数返回类型,第二个是参数类型
std::packaged_task<int(int)> mypt(mythread1); //把函数mythread通过packaged_task包装起来
std::thread t1(std::ref(mypt), 1); //线程直接开始执行,第二个参数作为线程入口函数的参数。
t1.join(); //可以调用这个等待线程执行完毕,不调用这个不太行,会崩溃。
std::shared_future<int> result_s(mypt.get_future());//通过get_future返回值直接构造了一个shared_future对象。
auto mythread_result = result_s.get();
std::thread t2(mythread2, std::ref(result_s));
t2.join(); //等线程执行完毕
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
三:原子操作std::atomic
<1>原子操作概念引出范例
互斥量:多线程编程中保护共享数据:锁,操作共享数据,开锁。
有两个线程,对一个变量进行操作,一个线程读变量值,另一个线程往这个变量中写值。
读线程A
int tmpvalue = atomvalue; //这个atomvalue 代表的是多个线程之间要共享的变量
写线程B
atomvalue = 6; //改成汇编代码,就有多条汇编代码执行。
把原子操作理解成:不需要用到互斥量加锁(无锁)技术的多线程并发编程方式。
原子操作:是在多线程中不会被打断的程序执行片段。原子操作,比互斥量效率上更胜一筹。
互斥量的加锁是针对一个代码段(几行代码),而原子操作针对的一般是一个变量,而不是一个代码段。
原子操作:一般指不可分割的操作,也就是说这种操作状态要么是完成的,要么是没完成的,不可能出现半完成状态。
std::atomic来代表原子操作;std::atomic是个类模板。其实std::atomic这个东西是用来封装某个类型的值。
<2>基本的std::atomic用法范例
std::atomic<int> g_mycout = 0; //我们封装了一个类型为int的对象(值);我们可以像操作一个int类型变量一样来操作g_mycout
//std::mutex g_my_mytex; //引入互斥量
void mythread() //线程入口函数
{
for (int i = 0; i < 100000000; i++)
{
//g_my_mytex.lock(); //用互斥量的方式时间比较慢
//g_mycout++;
//g_my_mytex.unlock();
g_mycout++; //对应的操作是原子操作(不会被打断)
}
return;
}
int main()
{
thread mytobj1(mythread);
thread mytobj2(mythread);
mytobj1.join();
mytobj2.join();
cout << "两个线程执行完毕,最终的g_mycout的结果是: " << g_mycout << endl;
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
再举例
std::atomic<bool> g_ifend = false; //线程退出标记,这里是原子操作,防止读和写乱套。
void mythread() {
std::chrono::milliseconds dura(1000); //1秒钟
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 dura(5000); //5秒钟
std::this_thread::sleep_for(dura);
g_ifend = true; //对原子对象的写操作,让线程自行运行结束
mytobj1.join();
mytobj2.join();
cout << "main主函数执行结束" << endl; //最后执行这句,整个进程退出
return 0;
}
<3>心得:一般用于统计或者计数(累计发出去了多少个数据包,累计接受到了多少个数据包)。