• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2025-05-18 20:16 Aet 隐藏边栏 |   抢沙发  2 
文章评分 1 次,平均分 5.0

描述

  1. 程序开始时,在UI显示之前,需要做一次网络请求,请求到的数据用于界面上一些内容的展示
    1. 这属于是一个一次性任务
  2. 除了一开始这个一次性任务之外,当UI选择了某个逻辑后,还会弹出另外一个新的界面
    1. 需要创建订单,需要显示该订单对应的二维码
    2. 在订单创建后,需要对该订单进行一定时间的轮询,查询订单状态
    3. 要做到这些功能,也可以用一次性任务的思维去实现(比如往线程池里抛任务,按任务类型,创建订单任务,完成后再抛一个查询订单状态,查询过期,再创建,再查询)
      外层一个死循环,一直在这样的事情,内部按一次性任务来
    4. 但是这里实现,我把他们放到了一起(创建完订单,就在同一个线程里开始查询)
    5. 总的来说,这属于一个长期任务

一次性任务

std::async

  1. 对于一次性任务,这里是用std::async启动了一个异步任务来处理

  1. 并在真正展示界面之前,调用futureget函数来获取结果
    1. 该函数先上报一些选项
    2. 调用futureget函数来获取结果
    3. 判断是否展示后续界面(用户是否被标记,网络请求是否成功)

  1. 代码中没体现的一点:
    1. ft_是作为类的成员变量,所以按理,应该在类的析构的时候,对ft_做如下处理
    2. 但是由于上面的逻辑,可以保证对get的调用,所以ft_在析构函数里也就不需要处理了
    3. 如果需要处理,但没有处理会怎么样?
      如果任务是死循环,那么最后阻塞在析构函数那里
      因为在类的析构里,最后会调用future的析构,而ft_ 的析构函数会隐式阻塞
      如果任务是耗时任务,同理也会阻塞一段时间,直到任务完成
    4. 案例见下文

长期任务

线程只创建一次

  1. 用原子变量来实现
    1. 当然也可以用std::call_once

std::async

  1. 由于是单个的长期任务,所以用std::async就可以了

future的隐式阻塞问题

  1. 上面讲到的future的隐式阻塞问题,就是在这里发现的,具体如下:
    1. 一开始future用的局部变量,对于这里的两个future,没有调用get
    2. 发现会有隐式阻塞问题,所以改成成员变量,解决问题
    3. 并且在析构的时候,统一调用了

  1. 然后,发现当启动多个订单线程的情况,一个订单完成时退出了,另一个订单还在进行,因为都是死循环,而这个另一个订单根本没扫过码,所以一直不会查到状态改变,所以会一直死循环,不会退出
    1. 用于在两个启动异步任务的地方都用了原子变量stop_flag_,解决了问题
    2. 当一个订单完成时,会设置这个原子变量,如下
    3. 这样两个线程就能正确退出了
    4. 但是,这一步的实现,并没有将stop_flag_作为参数传给create_pay

  1. 然后,又遇到了问题:
    1. 在上面的描述里讲过,这里的实现方式是在一个大循环(死循环)里面,还会有一个小循环,可能长达好几分钟
    2. 所以,当上面通过原子变量解决了这两个异步任务的退出问题后,发现,当主界面结束后,进程还会存在很长时间才会退出
    3. stop_flag_作为参数传给create_pay,在create_pay内部的小循环中,对这个变量进行了判断,如下(详细见上):
    4. 于是解决了这个问题

总结

std::future

  1. std::async启动的异步线程任务,要对future调用get
  2. 否则会发送future的隐式阻塞(阻塞与否看任务是否死循环)

声明:本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享