C++协程线程

等待--恢复,等待是挂起,协程执行完,再恢复.类似烧开水.
c++20协程几个基本概念:

可恢复类型

用于恢复协程类型,对应协程就是协程返回类型,调用者可通过它恢复协程,也可通过内部承诺型拿到协程返回值.

承诺类型

主要用来保存协程值,如果需要恢复协程时,需要通过承诺类型拿到协程句柄,再调用它的恢复方法.

协程句柄

主要用于访问底层协程帧,恢复和释放协程帧.
依赖顺序是可恢复类型-->承诺类型-->协程句柄,调用者通过可恢复类型恢复协程并拿到协程值.

协待,等待器,可等待

通过协待式来实现"等待",协待本质就是等待任务执行完成并拿到返回值,它主要依赖等待器来实现这个"等待"机制,可等待是帮助获取等待器的,不用太关注.

等待器如何实现等待,并取任务返回值的呢?
等待器.准备好协返回时,就会挂起协程,然后会执行等待器.挂起协,在挂起协中去调用任务,典型场景是把任务丢到线程中,或发起异步操作(注意要把协程句柄传到线程或异步回调里面),然后就返回给调用者,调用者不会阻塞,可以继续向下执行;

任务执行完成后,就可调用前面传入协程句柄.恢复来恢复协程表示任务执行完了,这时可通过等待器.恢复协得到懒任务的返回值了(也可能是无返回值);接下来就会从协待下一行继续执行协程函数直到协中.
依赖顺序是承诺类型-->初化挂起返回的等待器-->止挂起返回的等待器.
初化挂起挂起的目的很清楚,就是等待要完成的懒任务,具体由等待器来负责,那么何时需要止挂起呢,典型场景是同步等待协程完成时.
所以c++20协程中最重要的两个对象就是可恢复类型(恢复)和等待器(等待),其它都是"工具人",协程关键是要设计好如何使两个对象协作好.

等待线程中的协程执行完

常见实用协程使用场景是在线程中执行协程,这也是协程设计的重要目标:化"异步"为"同步!,通过简单代码来看看,如何调度协程线程中执行吧:

<型名 T>
构 承诺;<型名 T>[[未丢弃]]任务{
  用 承诺类型=承诺<T>;
  任务()=默认;

  动 符号 协待()常 无异{
    构 等待器{
      极 准备好协()常 无异{
        中 承诺.是准备好();
      }
      用 协程句柄=协程句柄<>;
      协程句柄 挂起协(协程句柄 连续)常 无异{
        承诺.连续=连续;
        中 协程句柄<承诺<T>>::从承诺(承诺);
      }
      T&&恢复协(){
        中 承诺.取结果();
      }

      承诺<T>&承诺;
    };
    中 等待器{*承诺};
  }

  T&&取结果(){
    中 承诺->取结果();
  }:
  任务(承诺<T>*承诺):承诺{承诺}{}

  承诺<T>*承诺=空针;<型名>友 构 承诺;
};<型名 T>
构 承诺{
  动 取中对象(){
    中 任务<T>{};
  }
  从不挂起 初始挂起()无异{{};}
  动 止挂起()无异{
    构 止等待器{
      极 准备好协()常 无异{中 假;}
      空 挂起协(协程句柄<承诺<T>>本协程)无异{&承诺=本协程.承诺();(承诺.连续)
          承诺.连续();
      }
      空 恢复协()常 无异{}
    };

    中 止等待器{};
  }
  空 未处理异常(){终止();}<型名 U>
  空 返回值(U&&)
  {
    结果.元 原位<1>(前向<U>());
  }

  T&&取结果(){(结果.索引()==2)
      再抛异常(<2>(结果));
    中 移动(<1>(结果));
  }

  极 是准备好(){
    中 结果.索引()!=0;
  }

  变量<单态,T,异常针>结果;
  协程句柄<>连续;
};

构 异步读文件{
  异步读文件(文系::路径 路径):路径{移动(路径)}{}
  极 准备好协()常 无异{中 假;}
  空 挂起协(协程句柄<>协程){
    动 工作=[,协程]()可变{
      输出<<本线程::取标识()<<"工作者线程:打开文件";
      动 流=入文件流{路径};
      输出<<本线程::取标识()<<"工作者线程:读文件";
      结果.赋值(入流缓冲步<>{},
                    入流缓冲步<>{});
      输出<<本线程::取标识()<<"工作者线程:恢复协程";
      协程();
      输出<<本线程::取标识()<<"工作者线程:退出";
    };
    线程{工作}.分离();
  }
  串 恢复协()无异{
    中 移动(结果);
  }:
  文系::路径 路径;
  串 结果;
};

任务<大小型>读文件(){
  输出<<本线程::取标识()<<"读文件():将异步读文件";
  常 动 结果=协待 异步读文件{"../主.c++"};
  输出<<本线程::取标识()<<"读文件():将中(大小"
            <<结果.大小()<<")\n";
  协中 结果.大小();
}

整 主(){
    动 任务=读文件();
    本线程::休息(1s);
    输出<<"文件大小="<<任务.取结果()<<'\n';
}

写了异步读文件等待器,通过协待挂起协程并等待线程完成读文件,当读完成恢复挂起的协程,得到读到的文件长度.
注意:这里在止挂起时,返回了止等待器来恢复之前等待异步读而挂起的协程,从而获得等待器返回值.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值