我们可以在 c++20 协程中使用 alloca() 或可变长度数组扩展吗?

Posted

技术标签:

【中文标题】我们可以在 c++20 协程中使用 alloca() 或可变长度数组扩展吗?【英文标题】:can we use alloca() or variable length array extentions in c++20 coroutines? 【发布时间】:2021-08-07 02:21:05 【问题描述】:

GCC C++ 编译器(还有许多其他 C++ 编译器)提供非标准扩展,例如

alloca() 用于基于堆栈的分配 可变长度数组,因为它们是 C 标准的一部分

从基本的角度来看,这些可以在 C++20 协程中使用吗?有可能吗?如果是的话,这是如何实现的?

据我了解,C++20 协程通常会在第一次调用时(即创建承诺对象时)为协程创建堆栈帧,因此需要知道协程堆栈的大小 -框架。

但是这与 alloca 或其他运行时动态堆栈分配不能很好地配合。

那么有可能吗?如果有,它是如何实现的?或者有什么影响?

【问题讨论】:

所有关于alloca 的可怕警告都适用。 VLA 的所有问题(即使作为扩展支持)都适用。并且代码的可移植性有限,如果可移植性无关紧要,那也没关系。 "从基本的角度来看"你的意思是什么? 【参考方案1】:

很遗憾,alloca 与 GCC 中的 C++20 协程不兼容。最糟糕的是编译器并没有发出警告。

此代码示例演示了不兼容:

#include <coroutine>
#include <iostream>

struct ReturnObject 
  struct promise_type 
    unsigned * value_ = nullptr;

    void return_void() 
    ReturnObject get_return_object() 
      return 
        .h_ = std::coroutine_handle<promise_type>::from_promise(*this)
      ;
    
    std::suspend_never initial_suspend()  return ; 
    std::suspend_never final_suspend() noexcept  return ; 
    void unhandled_exception() 
  ;

  std::coroutine_handle<promise_type> h_;
  operator auto() const  return h_; 
;

template<typename PromiseType>
struct GetPromise 
  PromiseType *p_;
  bool await_ready()  return false; 
  bool await_suspend(std::coroutine_handle<PromiseType> h) 
    p_ = &h.promise();
    return false;
  
  PromiseType *await_resume()  return p_; 
;

ReturnObject counter()

  auto pp = co_await GetPromise<ReturnObject::promise_type>;

  //unsigned a[1]; auto & i = a[0]; //this version works fine
  auto & i = *new (alloca(sizeof(unsigned))) unsigned(0); //and this not
  for (;; ++i) 
    pp->value_ = &i;
    co_await std::suspend_always;
  


int main()

  std::coroutine_handle<ReturnObject::promise_type> h = counter();
  auto &promise = h.promise();
  for (int i = 0; i < 5; ++i) 
    std::cout << *promise.value_ << std::endl;
    h();
  
  h.destroy();

https://gcc.godbolt.org/z/8zG446Esx

它应该打印0 1 2 3 4,但由于使用了alloca,它不准确

【讨论】:

这是一个有趣的发现。不过,这可能是 gcc 中的一个错误。 当我想到它时:递归可能也应该与协程一起使用。所以这也有一个运行时变量堆栈空间消耗...... 我刚刚用这个例子检查了MSVC,它也不支持协程中的alloca。所以它要么是一个常见的错误,要么是当前协程实现的一个常见限制。

以上是关于我们可以在 c++20 协程中使用 alloca() 或可变长度数组扩展吗?的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 协程协程的挂起和恢复 ② ( 协程挂起 和 线程阻塞 对比 )

我们可以在 Android Kotlin 的单个协程中下载多个文件吗

协程中的流

你应该知道的协程中的挂起转化小技巧

你应该知道的协程中的挂起转化小技巧

如何在 Kotlin 协程中使用 Sqldelight