美文网首页
多线程学习(十)

多线程学习(十)

作者: lxr_ | 来源:发表于2021-11-28 21:06 被阅读0次

所需头文件

#include "stdafx.h"
#include <iostream>
#include <thread>
#include <future>
using namespace std;

一.原子操作atomic续谈

一般atomic原子操作,针对++,--,+=,&=,|=,^=是支持的。其他可能不支持
上一篇我们已经验证++是支持原子操作的,下面可以测试一下+=
测试如下:

std::atomic<int> global_value = 0;  //原子整形变量,可以像整形变量一样使用
//线程入口函数
void MyThread()
{
    for (int i = 0; i < 10000000; i++)
    {
        global_value++;                 //对应的操作位原子操作,不会被打断
        global_value += 1;              
        //global_value = global_value + 1;  //结果不对,不支持原子操作

    }
}

int main()
{
thread T1(MyThread);
thread T2(MyThread);
//创建两个线程,都会对全局变量修改

T1.join();
T2.join();

cout << "两个线程执行完毕,最终结果:" << endl;
cout << global_value << endl;

return 0;

}
经过多次测试,发现程序运行结果都为下面这张图片所示,故++和+=都是支持原子操作的,而global_value = global_value + 1是不支持的,其他运算可以自行测试。

二.sd::async深入谈

对前面讲的async的补充和回顾
2.1)std::async参数详述,根据前面一篇多线程学习(八)所述,async用于创建异步任务
介绍了延std::launch::deferred(迟调用参数),以及std::launch::async(强制创建线程)
如果系统资源紧张,则使用std::thread()创建线程,可能导致创建线程失败
std::async()一般不叫创建线程(即使能够创建线程),而一般叫异步任务
std::async和std::thread明显不同就是async有时候并不创建线程
a)如果用std::launch::deferred参数来调用async会怎么样?
根据前面多线程学习(八)所述,我们知道其并不创建新线程,且延迟到future对象调用get或wait函数时才执行线程入口函数,如果未调用get或wait函数,则不会执行线程入口函数
b)****std::launch::async:强制异步任务在新线程上执行,意味着系统必须创建新线程来运行线程入口函数
c)std::launch::async|std::launch::deferred:联合使用看起来和async单个使用一样的效果(因为系统资源足够)
这里的“|”(按位或)意味着调用async的行为可能是创建新线程并立即执行也可能是没有创建新线程并且延迟到调用get函数才开始执行入口函数
d)不带额外参数,即使用默认参数,只给async一个入口函数名
多线程学习(八)中,当时说默认值是std::launch::async,这里讲错了,其实是std::launch::async|std::launch::deferred(联合调用) ,和c)一样的效果
换句话说:系统会自行决定是异步(创建新线程)还是同步(不创建新线程)方式运行
那么系统如何决定是异步(创建新线程)还是同步(不创建新线程)方式运行???

2.2)std::async和std::thread的区别
std::thread创建线程,如果系统资源紧张,则创建线程失败,整个程序崩溃
std::thread创建线程的方式下,如果线程入口函数返回值,想获取这个值不太容易,可能需要定义全局变量
std::async创建异步任务,可能创建线程也可能不创建,并且这种方式很容易拿到线程入口函数的返回值

由于系统资源限制:
1)如果std::thread创建的线程太多,则可能创建失败,系统报告异常、崩溃
2)如果用std::async,一般不会报异常,因为如果系统资源紧张导致无法创建线程的时候,async这种不加额外参数的调用就不会创建新线程。而是后续谁调用了get函数来请求结果,这个异步任务就运行在执行这条get()语句所在的线程上
如果强制创建新线程,就要使用std::launch::async参数。代价是系统资源紧张时,程序崩溃。
3)经验:一个程序里,线程数量不宜超过100-200

2.3)std::async不确定性问题的解决
不加额外参数的std::async调用,让系统自行决定是否创建新线程
有个问题是,不加额外参数时,这个异步任务到底有没有被推迟执行???(即std::launch::async还是std::launch::deferred
这个就涉及到了多线程学习(九)中所讲的std::future对象wait_for函数
根据wait_for函数的返回值来确定系统自行决定的参数
下面进行测试
线程入口函数

int MyThread()
{
    cout << "MyThread start thread id = " << std::this_thread::get_id() << endl;

    std::chrono::milliseconds duration(5000);  //5000ms=5s
    std::this_thread::sleep_for(duration);     //停止运行5s

    return 1;
}

主函数

int main()
{
    cout << "main start thread id = " << std::this_thread::get_id() << endl;

    std::future<int> result = std::async( MyThread);
    std::future_status status = result.wait_for(0s);  //支持重载后缀,等价于std::chrono::seconds(0);
    if (status == std::future_status::deferred)
    {
        //线程被延迟执行(系统资源紧张,采用了std::launch::deferred参数)
        cout << result.get() << endl; //这时才调用MyThread
    }
    else
    {
        if (status == std::future_status::ready)
        {
            //线程成功返回
            cout << "线程成功执行完毕并返回!" << endl;
            cout << result.get() << endl;
        }
        else if (status == std::future_status::timeout)
        {
            //线程运行超时
            cout << "线程运行超时" << endl;
            cout << result.get();
        }
    }

    return 0;
}

相关文章

网友评论

      本文标题:多线程学习(十)

      本文链接:https://www.haomeiwen.com/subject/vzshxrtx.html