我怀疑它可以移植,但有没有解决方案?我认为可以通过创建备用堆栈并在功能输入上重置SP,BP和IP,并使产量保存IP并恢复SP + BP来完成。析构函数和异常安全似乎很棘手,但可以解决。

它已经完成了吗?这不可能吗?

有帮助吗?

解决方案

是的可以完成没有问题。您只需要一个小的汇编代码来将调用堆栈移动到堆上新分配的堆栈。

我会查看 boost :: coroutine

你应该注意的一件事是堆栈溢出。在大多数操作系统上,溢出堆栈将导致段错误,因为未映射虚拟内存页。但是,如果您在堆上分配堆栈,则无法获得任何保证。 请记住这一点。

其他提示

在POSIX上,您可以使用makecontext()/ swapcontext()例程来可移植地切换执行上下文。在Windows上,您可以使用光纤API。否则,您只需要一些胶水装配代码来切换机器上下文。我已经使用ASM(对于AMD64)和swapcontext()实现了协同程序;既不是很难。

对后代来说,

Dmitry Vyukov的奇妙的网站有一个聪明的伎俩使用ucontext和setjump在c ++中模拟协同程序。

此外,Oliver Kowalke的上下文库已最近接受进入提升,所以希望我们很快就能看到更新版本的boost.coroutine,它可以在x86_64上运行。

没有简单的方法来实现协同程序。由于协程本身不像C / C ++的堆栈抽象,就像线程一样。因此,如果没有语言级别的更改,就无法支持它。

目前(C ++ 11),所有现有的C ++协程实现都基于程序集级别的黑客攻击,难以跨越平台安全可靠。为了可靠,它需要是标准的,并由编译器处理而不是黑客攻击。

标准提案 - N3708 为此。如果您有兴趣,请查看它。

如果可能的话,使用迭代器可能比使用协程更好。这样你可以继续调用 next()来获取下一个值,但你可以将你的状态保存为成员变量而不是局部变量。

它可能使事情更易于维护。另一个C ++开发人员可能不会立即理解协程,而他们可能更熟悉迭代器。

对于那些想要了解他们如何在C ++中以可移植的方式利用Coroutines的人̶ o̶ u̶ ̶ W̶ I̶ L̶ L̶ ̶ H̶ A̶ V̶ E̶ ̶ T̶ O̶ ̶ W̶ A̶ I̶ T̶ ̶ F̶ O̶ R̶ ̶ C̶ +̶ +̶ 1̶ 7̶等待结束了(见下文)!标准委员会正在研究该功能,请参阅 N3722论文。总结本文的当前草案,而不是Async和Await,关键字将是可恢复的,等待。

看一下Visual Studio 2015中的实验性实现,以便与Microsoft的实验性实现一起使用。看起来clang还没有实现。

来自Cppcon的一个很好的演讲 Coroutines负面开销抽象概述了使用Coroutines的好处C ++以及它如何影响代码的简单性和性能。

目前我们仍然需要使用库实现,但在不久的将来,我们将使用协同程序作为核心C ++特性。

更新: 看起来协程实现是针对C ++ 20的,但是作为C ++ 17的技术规范发布( p0057r2 )。 Visual C ++,clang和gcc允许您选择使用编译时标志。

用于协同序列的可移植C ++库的COROUTINE 指向您在正确的方向?它似乎是一个优雅的解决方案,经历了时间的考验.....它已经9岁了!

在DOC文件夹中是Keld Helsgaun撰写的用于协同序列的便携式C ++库的pdf文件,其中描述了该库并提供了使用它的简短示例。

[更新]我实际上是自己成功使用它。好奇心让我变得更好,所以我调查了这个解决方案,发现它非常适合我已经工作了一段时间的问题!

我不认为在C ++中有很多完整的,干净的实现。我喜欢的一个尝试是 Adam Dunkels的protothread库

另见 Protothreads:简化内存受限嵌入式系统的事件驱动编程在ACM数字图书馆和维基百科主题 Protothread 中进行讨论,

新图书馆 Boost .Context ,今天发布了用于实现协同程序的便携式功能。

这是一个旧线程,但我想建议使用Duff的设备,而不依赖于OS(据我记得):

使用Duff设备 C coroutines

作为一个例子,这里是一个telnet库我修改为使用协程而不是fork / threads: 使用协同程序的Telnet cli库

由于C99之前的标准C本质上是C ++的真正子集,因此在C ++中也能很好地工作。

它基于(cringe)宏,但是以下站点提供了一个易于使用的生成器实现: http://www.codeproject.com/KB/cpp/cpp_generators.aspx

我想出了一个实现没有asm 代码。我们的想法是使用系统的线程创建函数来初始化堆栈和上下文,并使用setjmp / longjmp来切换上下文。但它不便携,如果您有兴趣,请参阅棘手的pthread版本

https://github.com/tonbit/coroutine 是C ++ 11单曲.h支持resume / yield / await primitives和Channel模型的非对称协程实现。它是通过ucontext / fiber实现的,不依赖于boost,在linux / windows / macOS上运行。这是学习在c ++中实现协同程序的一个很好的起点。

查看我的实现,它说明了asm黑客攻击点并且很简单:

https://github.com/user1095108/generic/blob/master /coroutine.hpp

你应该总是考虑使用线程;特别是在现代硬件中。如果你的工作可以在协同例程中进行逻辑分离,那么使用线程意味着工作实际上可以由不同的执行单元(处理器核心)同时完成。

但是,也许你确实想要使用协同程序,也许是因为你有一个经过良好测试的算法,这个算法已经以这种方式编写和测试,或者因为你正在移植以这种方式编写的代码。

如果你在Windows中工作,你应该看一下光纤。纤维将在操作系统的支持下为您提供类似协程的框架。

我不熟悉其他操作系统,以推荐替代品。

WvCont WvStreams 的一部分,它实现了所谓的半协同程序。这些比完全协同程序更容易处理:你调用它,然后它会回复给那个调用它的人。

它使用更灵活的WvTask实现,它支持全开程协同程序;你可以在同一个图书馆找到它。

适用于win32和Linux,至少适用于任何其他Unix系统。

我尝试使用C ++ 11和线程自己实现协同程序:

#include <iostream>
#include <thread>

class InterruptedException : public std::exception {
};

class AsyncThread {
public:
    AsyncThread() {
        std::unique_lock<std::mutex> lock(mutex);
        thread.reset(new std::thread(std::bind(&AsyncThread::run, this)));
        conditionVar.wait(lock); // wait for the thread to start
    }
    ~AsyncThread() {
        {
            std::lock_guard<std::mutex> _(mutex);
            quit = true;
        }
        conditionVar.notify_all();
        thread->join();
    }
    void run() {
        try {
            yield();
            for (int i = 0; i < 7; ++i) {
                std::cout << i << std::endl;
                yield();
            }
        } catch (InterruptedException& e) {
            return;
        }
        std::lock_guard<std::mutex> lock(mutex);
        quit = true;
        conditionVar.notify_all();
    }
    void yield() {
        std::unique_lock<std::mutex> lock(mutex);
        conditionVar.notify_all();
        conditionVar.wait(lock);
        if (quit) {
            throw InterruptedException();
        }
    }
    void step() {
        std::unique_lock<std::mutex> lock(mutex);
        if (!quit) {
            conditionVar.notify_all();
            conditionVar.wait(lock);
        }
    }
private:
    std::unique_ptr<std::thread> thread;
    std::condition_variable conditionVar;
    std::mutex mutex;
    bool quit = false;
};

int main() {
    AsyncThread asyncThread;
    for (int i = 0; i < 3; ++i) {
        std::cout << "main: " << i << std::endl;
        asyncThread.step();
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top