C++ 了解C+提案N3650中关于可恢复功能的示例+;1y

C++ 了解C+提案N3650中关于可恢复功能的示例+;1y,c++,c++14,C++,C++14,考虑以下示例,该示例取自: 我可能遗漏了一些东西,但是如果我理解了async和wait那么,当效果等同于写作时,用上面的例子展示这两种结构的有用性有什么意义呢 int cnt = 0; do { cnt = streamR.read(512, buf).get(); if (cnt == 0) break; cnt = streamW.write(cnt, buf).get(); } while (cnt > 0); 如果read().get()和write

考虑以下示例,该示例取自:

我可能遗漏了一些东西,但是如果我理解了
async
wait
那么,当效果等同于写作时,用上面的例子展示这两种结构的有用性有什么意义呢

int cnt = 0;
do {
   cnt = streamR.read(512, buf).get();
   if (cnt == 0)
      break;
   cnt = streamW.write(cnt, buf).get();
} while (cnt > 0);

如果
read().get()
write().get()
调用都是同步的?

我认为想法是
streamR.read()
streamW.write()
调用是异步I/O操作和返回未来,由
wait
表达式自动等待

因此,等效的同步版本必须调用
future::get()
来获得结果,例如

int cnt = 0;
do {
   cnt = streamR.read(512, buf).get();
   if (cnt == 0)
      break;
   cnt = streamW.write(cnt, buf).get();
} while (cnt > 0);
您指出这里没有并发是正确的。但是,在可恢复函数的上下文中,
wait
使行为与上面的代码片段不同。当到达
wait
时,函数将返回一个
future
,因此即使可恢复函数在等待其他结果时在
wait
处被阻止,函数调用方也可以继续而不阻塞(例如,在这种情况下,
read()
write()
调用以完成)Resubable函数可能会异步恢复运行,因此当调用方执行其他操作时,结果在后台可用。

更完整的示例(希望正确):


不同之处在于可恢复函数可以由不同的线程执行:不同的线程可以在每个恢复/暂停点之后恢复(可恢复函数的)执行。

等待关键字不等于在将来调用get。你可以这样看,假设你从这个开始:

future<T> complex_function()
{
     do_some_stuff();
     future<Result> x = await some_async_operation();
     return do_some_other_stuff(x);
}
future复数函数()
{
做些什么;
future x=等待一些异步操作();
返回做一些其他事情(x);
}
这在功能上与

future<T> complex_function()
{
     do_some_stuff();
     return some_async_operation().then([=](future<Result> x) {
         return do_some_other_stuff(x);
     });
}
future复数函数()
{
做些什么;
返回一些异步操作()。然后([=](未来x){
返回做一些其他事情(x);
});
}
请或多或少注意,由于存在一些资源管理方面的影响,在
do_some_stuff
中创建的变量不应复制到执行
do_some_other_stuff
中,就像lambda版本一样

第二个变量更清楚地说明了调用时会发生什么

  • 调用
    complex\u函数时,将同步调用
    do\u some\u stuff()
  • 某些异步操作被异步调用,并在将来产生结果。执行此操作的确切时间取决于实际的异步调用实现,它可能在使用线程时立即执行,也可能在使用延迟执行时调用
    .get()
    时立即执行
  • 我们不会立即执行
    do\u some\u other\u stuff
    ,而是将其链接到步骤2中获得的未来。这意味着只要
    某个异步操作的结果准备就绪,就可以执行该操作,但不能在此之前执行。除此之外,它的执行时刻由运行时决定。如果实施仅包装
    ,则
    提案,这意味着它将继承未来母公司的执行人/启动政策(根据N3558)
  • 函数返回表示最终结果的最后一个未来。注意,这需要是将来的事情,因为函数体的一部分是异步执行的

  • 下面是不使用wait的示例函数的正确翻译:

    struct Copy$StackFrame {
      promise<void> $result;
      input_stream& streamR;
      output_stream& streamW;
      int cnt;
      char buf[512];
    };
    using Copy$StackPtr = std::shared_ptr<Copy$StackFrame>;
    
    future<void> Copy(input_stream& streamR, output_stream& streamW) {
      Copy$StackPtr $stack{ new Copy$StackFrame{ {}, streamR, streamW, 0 } };
      future<int> f$1 = $stack->streamR.read(512, stack->buf);
      f$1.then([$stack](future<int> f) { Copy$Cont1($stack, std::move(f)); });
      return $stack->$result.get_future();
    }
    
    void Copy$Cont1(Copy$StackPtr $stack, future<int> f$1) {
      try {
        $stack->cnt = f$1.get();
        if ($stack->cnt == 0) {
          // break;
          $stack->$result.set_value();
          return;
        }
        future<int> f$2 = $stack->streamW.write($stack->cnt, $stack->buf);
        f$2.then([$stack](future<int> f) { Copy$Cont2($stack, std::move(f)); });
      } catch (...) {
        $stack->$result.set_exception(std::current_exception());
      }
    }
    
    void Copy$Cont2(Copy$StackPtr $stack, future<int> f$2) {
      try {
        $stack->cnt = f$2.get();
        // while (cnt > 0)
        if (cnt <= 0) {
          $stack->$result.set_value();
          return;
        }
        future<int> f$1 = $stack->streamR.read(512, stack->buf);
        f$1.then([$stack](future<int> f) { Copy$Cont1($stack, std::move(f)); });
      } catch (...) {
        $stack->$result.set_exception(std::current_exception());
      }
    }
    
    struct Copy$StackFrame{
    承诺$结果;
    输入流&streamR;
    输出流&streamW;
    int-cnt;
    char-buf[512];
    };
    使用Copy$StackPtr=std::shared\u ptr;
    未来副本(输入流和流器、输出流和流器){
    复制$StackPtr$stack{new Copy$StackFrame{{},streamR,streamW,0};
    未来f$1=$stack->streamR.read(512,stack->buf);
    f$1。然后([$stack](未来f){Copy$Cont1($stack,std::move(f));});
    返回$stack->$result.get_future();
    }
    无效副本$Cont1(副本$StackPtr$stack,未来f$1){
    试一试{
    $stack->cnt=f$1.get();
    如果($stack->cnt==0){
    //中断;
    $stack->$result.set_value();
    返回;
    }
    未来f$2=$stack->streamW.write($stack->cnt,$stack->buf);
    然后([$stack](未来的f){Copy$Cont2($stack,std::move(f));});
    }捕获(…){
    $stack->$result.set_异常(std::current_exception());
    }
    }
    无效副本$Cont2(副本$StackPtr$stack,未来f$2){
    试一试{
    $stack->cnt=f$2.get();
    //而(cnt>0)
    如果(cnt$result.set_value();
    返回;
    }
    未来f$1=$stack->streamR.read(512,stack->buf);
    f$1。然后([$stack](未来f){Copy$Cont1($stack,std::move(f));});
    }捕获(…){
    $stack->$result.set_异常(std::current_exception());
    }
    }
    

    正如您所看到的,这里的编译器转换非常复杂
    版本,原始的
    副本
    在第一次异步调用完成后立即返回其未来。

    对于这两个代码示例之间的差异的含义,我有相同的问题。让我们重新编写一点,以便更完整

        // Having two functions
        future<void> f (istream&streamR, ostream&streamW) async
        {  int cnt = 0;
           do {
              cnt = await streamR.read(512, buf);
              if (cnt == 0)
                 break;
              cnt = await streamW.write(cnt, buf);
           } while (cnt > 0);
        }
        void g(istream&streamR, ostream&streamW)
        {  int cnt = 0;
           do {
              cnt = streamR.read(512, buf).get();
              if (cnt == 0)
                 break;
              cnt = streamW.write(cnt, buf).get();
           } while (cnt > 0);
        }
        // what is the difference between
        auto a = f(streamR, streamW);
        // and 
        auto b = async(g, streamR, streamW);
    
    //有两个函数
    未来f(istream和streamR、ostream和streamW)异步
    {int cnt=0;
    做{
    cnt=等待流读取(512,buf);
    如果(cnt==0)
    打破
    cnt=等待流w.write(cnt,buf);
    }而(cnt>0);
    }
    空隙g(istream&streamR、ostream&streamW)
    {int cnt=0;
    做{
    cnt=streamR.read(512,buf.get();
    如果(cnt==0)
    打破
    cnt=streamW.write(cnt,buf.get();
    }而(cnt>0);
    }
    //两者的区别是什么
    自动a=f(流线型,st
    
    future<T> complex_function()
    {
         do_some_stuff();
         return some_async_operation().then([=](future<Result> x) {
             return do_some_other_stuff(x);
         });
    }
    
    struct Copy$StackFrame {
      promise<void> $result;
      input_stream& streamR;
      output_stream& streamW;
      int cnt;
      char buf[512];
    };
    using Copy$StackPtr = std::shared_ptr<Copy$StackFrame>;
    
    future<void> Copy(input_stream& streamR, output_stream& streamW) {
      Copy$StackPtr $stack{ new Copy$StackFrame{ {}, streamR, streamW, 0 } };
      future<int> f$1 = $stack->streamR.read(512, stack->buf);
      f$1.then([$stack](future<int> f) { Copy$Cont1($stack, std::move(f)); });
      return $stack->$result.get_future();
    }
    
    void Copy$Cont1(Copy$StackPtr $stack, future<int> f$1) {
      try {
        $stack->cnt = f$1.get();
        if ($stack->cnt == 0) {
          // break;
          $stack->$result.set_value();
          return;
        }
        future<int> f$2 = $stack->streamW.write($stack->cnt, $stack->buf);
        f$2.then([$stack](future<int> f) { Copy$Cont2($stack, std::move(f)); });
      } catch (...) {
        $stack->$result.set_exception(std::current_exception());
      }
    }
    
    void Copy$Cont2(Copy$StackPtr $stack, future<int> f$2) {
      try {
        $stack->cnt = f$2.get();
        // while (cnt > 0)
        if (cnt <= 0) {
          $stack->$result.set_value();
          return;
        }
        future<int> f$1 = $stack->streamR.read(512, stack->buf);
        f$1.then([$stack](future<int> f) { Copy$Cont1($stack, std::move(f)); });
      } catch (...) {
        $stack->$result.set_exception(std::current_exception());
      }
    }
    
        // Having two functions
        future<void> f (istream&streamR, ostream&streamW) async
        {  int cnt = 0;
           do {
              cnt = await streamR.read(512, buf);
              if (cnt == 0)
                 break;
              cnt = await streamW.write(cnt, buf);
           } while (cnt > 0);
        }
        void g(istream&streamR, ostream&streamW)
        {  int cnt = 0;
           do {
              cnt = streamR.read(512, buf).get();
              if (cnt == 0)
                 break;
              cnt = streamW.write(cnt, buf).get();
           } while (cnt > 0);
        }
        // what is the difference between
        auto a = f(streamR, streamW);
        // and 
        auto b = async(g, streamR, streamW);