문제
나는 그것을 의심 할 수 있습 portably 지만,어떤 해결책이 있습니까?나는 그것을 할 수 있을 작성하여 다른 스택하고 재설정 SP,BP,IP 에 기능 항목 및 수확량 저장 IP 과 복원 SP+BP.소멸자 및 예외 안전 까다로워 보이지만 해결할 수 있습니다.
되었는가?불가능한가?
해결책
네 할 수 있습니다 문제없이. 호출 스택을 힙에 새로 할당 된 스택으로 옮기기위한 작은 어셈블리 코드 만 있으면됩니다.
나는 할 것이다 를보세요 부스트 :: 코 루틴 도서관.
당신이 조심해야 할 것은 스택 오버플로입니다. 대부분의 운영 체제에서 오버플레이션에서 스택은 가상 메모리 페이지가 매핑되지 않기 때문에 segfault가 발생합니다. 그러나 힙에 스택을 할당하면 보장이 없습니다. 그냥 명심하십시오.
다른 팁
POSIX에서는 makecontext ()/swapcontext () 루틴을 사용하여 실행 컨텍스트를 포괄적으로 전환 할 수 있습니다. Windows에서는 섬유 API를 사용할 수 있습니다. 그렇지 않으면 필요한 것은 기계 컨텍스트를 전환하는 약간의 접착제 어셈블리 코드입니다. ASM (AMD64의 경우)과 SwapContext ()가있는 코 루틴을 구현했습니다. 둘 다서도 어렵지 않습니다.
후손을 위해
Dmitry Vyukov 's 놀라운 웹 사이트 C ++에서 시뮬레이션 된 코 루틴에 UCONTEXT 및 SETJUMP를 사용하여 영리한 트릭이 있습니다.
또한 Oliver Kowalke의 맥락 도서관도있었습니다 최근에 받아 들여졌습니다 Boost는 곧 x86_64에서 작동하는 Boost.coroutine의 업데이트 된 버전을 볼 수 있기를 바랍니다.
Coroutine을 구현하는 쉬운 방법은 없습니다. Coroutine 자체는 C/C ++의 스택 추상화가 스레드와 마찬가지로 사용되지 않기 때문입니다. 따라서 지원을 위해 언어 수준 변경 없이는 지원할 수 없습니다.
현재 (C ++ 11), 기존의 모든 C ++ Coroutine 구현은 모두 어셈블리 레벨 해킹을 기반으로하며 플랫폼을 통해 안전하고 신뢰할 수있는 교차로가 어렵습니다. 신뢰할 수 있으려면 표준이어야하며 해킹보다는 컴파일러가 처리해야합니다.
거기에 표준 제안 -N3708 이것을 위해. 관심이 있으시면 확인하십시오.
가능한 경우 코 루틴보다 반복자로 더 나을 수 있습니다. 그렇게하면 계속 전화 할 수 있습니다 next()
다음 값을 얻으려면 상태를 로컬 변수 대신 멤버 변수로 유지할 수 있습니다.
일을 더욱 관리 할 수있게 할 수 있습니다. 다른 C ++ 개발자는 코 루틴을 즉시 이해하지 못하는 반면 반복자에 더 익숙 할 수 있습니다.
를 알고 싶은 사람들은 그들이 어떻게 활용할 수 있습 하에서 휴대용 방식에서는 C++당신을 기다려야 할 것이를 위한 C++17 야기이다(아래 참조)!표준 위원회는 작업에 기능 표시 N3722paper.요약하면 현재 초안의 종이 대신,비동기와 기다리고 있는 키워드는 것이 다시 시작 가능,그리고 기다리고 있습니다.
을 살펴 실험적인 구현을 Visual Studio 에서 2015 년을 재생하는 Microsoft 의 실험적인 구현합니다.그것처럼 보이지 않는 그 소리는 아직 구현.
거기에 좋은 이야기에서 Cppcon 하는 부정적인 오버헤드 추출 개략을 사용하는의 이득 하는 C++에서 어떻게 영향을 미치는 단순성과 성능의 코드입니다.
현재 우리는 여전히 사용하는 라이브러리 구현,하지만 가까운 미래에 우리가 하로 core C++기능입니다.
업데이트:처럼 보이는 coroutine 구현할 예정을 위한 C++20,그러나이었다로 출시된 기술 사양으로 C++17(p0057r2).Visual C++,그 소리와 gcc 수신을 거부할 수 있을 사용하여 컴파일 시기이다.
하다 코 루틴 코 루틴 시퀀싱을위한 휴대용 C ++ 라이브러리 당신을 올바른 방향으로 가리십니까? 시간의 시험을 지속시킨 우아한 솔루션처럼 보입니다 ..... 9 살입니다!
DOC 폴더에는 논문의 PDF가 있으며 Keld Helsgaun의 Coroutine 시퀀싱을위한 휴대용 C ++ 라이브러리가 라이브러리를 설명하고이를 사용하는 짧은 예제를 제공합니다.
업데이트] 저는 실제로 직접 사용하고 있습니다. 호기심이 나에게 더 나아졌다. 그래서 나는이 솔루션을 살펴 보았고, 내가 한동안 작업했던 문제에 적합하다는 것을 알았다!
나는 C ++에 많은 본격적인 깨끗한 구현이 있다고 생각하지 않습니다. 내가 좋아하는 시도는 하나입니다 Adam Dunkels의 프로토 스레드 도서관.
또한보십시오 Protothreads : 메모리 제약 임베디드 시스템의 이벤트 중심 프로그래밍 단순화 ACM 디지털 라이브러리 및 Wikipedia Topic의 토론에서 프로토 스레드,
새로운 도서관, boost.context, 오늘 코 루틴 구현을위한 휴대용 기능으로 오늘 출시되었습니다.
이것은 오래된 스레드이지만, os 의존적이지 않은 Duff의 장치를 사용하여 해킹을 제안하고 싶습니다 (내가 기억하는 한).
예를 들어, 여기에 포크/스레드 대신 코 루틴을 사용하도록 수정 한 텔넷 라이브러리가 있습니다.텔넷 CLI 라이브러리를 사용하여 코 루틴을 사용합니다
그리고 C99 이전의 표준 C는 본질적으로 C ++의 실제 하위 집합이기 때문에 C ++에서도 잘 작동합니다.
(Cringe) 매크로를 기반으로하지만 다음 사이트는 사용하기 쉬운 발전기 구현을 제공합니다. http://www.codeproject.com/kb/cpp/cpp_generator.aspx
구현을 생각해 냈습니다 ASM없이 암호. 아이디어는 시스템 스레드 생성 기능을 사용하여 스택 및 컨텍스트를 초기화하고 SetJMP/LongJMP를 사용하여 컨텍스트를 전환하는 것입니다. 그러나 휴대용이 아닙니다 까다로운 pthread 버전 관심이 있다면.
https://github.com/tonbit/coroutine C ++ 11 단일 .h 비대칭 코 루틴 구현 이력서/수율/차단 프리미티브 및 채널 모델을 지원합니다. Linux/Windows/MacOS에서 실행되는 부스트에 따라 UContext/Fiber를 통해 구현됩니다. C ++에서 코 루틴 구현을 배우는 것이 좋은 출발점입니다.
내 구현을 확인하십시오. ASM 해킹 지점을 보여주고 간단합니다.
https://github.com/user1095108/generic/blob/master/coroutine.hpp
대신 스레드 사용을 항상 고려해야합니다. 특히 현대 하드웨어에서. 공동 경로에서 논리적으로 분리 될 수있는 작업이있는 경우 스레드를 사용하면 별도의 실행 장치 (프로세서 코어)에 의해 작업이 실제로 동시에 수행 될 수 있음을 의미합니다.
그러나 아마도 당신은 아마도 당신이 이미 쓰여지고 테스트 한 잘 테스트 된 알고리즘을 가지고 있거나, 그런 식으로 작성된 코드를 포팅하고 있기 때문에 아마도 코 루틴을 사용하고 싶을 것입니다.
Windows에서 일하는 경우 섬유. 섬유는 OS에서 지원하는 코 루틴과 같은 프레임 워크를 제공합니다.
다른 OS에 익숙하지 않습니다. 대안을 추천합니다.
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();
}
}