【问题标题】:Rationale behind the resumable functions restrictions可恢复功能限制背后的基本原理
【发布时间】:2014-05-02 07:23:09
【问题描述】:

在关于resumable functions的论文中,在限制部分列出了三个限制:

  • 可恢复函数不能使用可变数量的参数。对于需要可变参数的情况,可以将参数解包放在一个函数中,该函数在对参数进行解包后调用可恢复函数。
  • 可恢复函数的返回类型必须是future<T>shared_future<T>。 T 的限制是由std::future 定义的,不是本提案,但T 必须是可复制或可移动的类型,或“void”。还必须可以构造一个不带参数的T 变量;也就是说,如果它是类类型,它必须有一个可访问的(隐式或显式)默认构造函数。
  • 等待表达式可能不会出现在异常处理程序的主体中,并且不应在执行线程持有任何类型的锁时执行。

这种限制背后一定有原因,由于我对并发性缺乏了解,我无法推断出原因是什么。有人可以启发我这个话题吗?

可变数量的参数

这个限制是指 C 风格的可变参数函数还是 C++11 可变参数模板的?

  • 如果是C风格的,限制的原因与va_*宏所做的魔术有关?
  • 如果指的是可变参数模板函数,我假设限制必须与参数包的解包有关,而不是函数是模板的事实(没有关于模板可恢复函数的措辞,所以我假设它们是合法的)。

在这两种情况下,我都认为编译器可以足够聪明地推断出要使用的函数。

默认可构造和可复制/可移动类型

我理解返回 std::futurestd::shared_future 背后的原因,但我猜测可用类型背后的限制原因与期货可以使用的类型有关。

因此,该论文提议使用两个新关键字(resumable 和 await)扩展该语言,这些关键字提供可恢复函数的行为,但最终它信任现有的构造来在函数和函数之间传输可恢复函数的返回值调用者。

为什么不也为返回值提出某种语言扩展?这可以(也许)释放对默认可构造和可复制/可移动类型的限制,并修复返回类型和返回类型之间的 assimetry:

因此应该注意,从外部(调用者)和内部观察到的函数行为之间存在不对称:从外部角度来看,函数在第一个暂停点返回 future<T> 类型的值,而内部观点是该函数通过 return 语句返回 T 类型的值 (...)

没有可等待的异常处理程序,也没有可等待的锁定线程

我想在捕获异常的同时等待某些东西是没有意义的,但我对锁定线程的限制一无所知。

【问题讨论】:

    标签: c++ c++14 resume


    【解决方案1】:

    我很确定所有这些限制都与可恢复函数的上下文必须“保存”和“恢复”这一事实有关——我希望该机制会创建一个临时的“堆栈副本”或相似的东西。所以:

    • 可变数量的参数

      这确实意味着使用va_arg 功能的事情——不是因为涉及到宏,而是因为外部代理不可能知道实际参数的数量——对于printf,你必须阅读格式字符串,对于其他一些人,最后一个标有NULL。那么需要保存多少上下文呢?

    • 锁定的线程

      所以我们刚刚说“我们不希望这个线程被中断”,然后我们说“现在让我们运行别的东西”。这就像在走进浴缸时说“拜托,在任何情况下我都不能在洗澡时被打扰”,同时说“你能在 2 分钟内给我打电话吗……”——假设洗澡时间超过 2分钟,其中之一将是不真实的。

    • 默认构造

      我很确定这里的逻辑是,如果要构造的返回值必须将参数传递给构造函数,这会使整个概念变得非常复杂。你会怎么形容这样的事情?而且您还必须在暂停状态下“坚持”这些论点。同样,使上下文的保存更加复杂。

    【讨论】:

    • 是的,关于堆栈的副本,​​你是对的,在3.2有了这个原型实现,每个可恢复函数都有自己的侧堆栈。侧栈是一个栈,独立于线程的主栈,由编译器在调用可恢复函数时分配。
    • 这不是我所期待的答案,但它很好地涵盖了我对这个问题的疑问,感谢您的努力:✔
    猜你喜欢
    • 2023-04-08
    • 2011-03-11
    • 2015-04-25
    • 1970-01-01
    • 2015-08-18
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    相关资源
    最近更新 更多