Współprogram — Coroutine

Współprogramy to składniki programu komputerowego, które uogólniają podprogramy dla wielozadaniowości bez wywłaszczania , umożliwiając zawieszenie i wznowienie wykonywania. Współprogramy doskonale nadają się do implementowania znanych komponentów programu, takich jak zadania kooperacyjne , wyjątki , pętle zdarzeń , iteratory , nieskończone listy i potoki .

Według Donalda Knutha , Melvin Conway ukuł termin „ korutyna” w 1958 roku, kiedy zastosował go do konstrukcji programu montażowego . Pierwsze opublikowane wyjaśnienie współprogramu pojawiło się później, w 1963 roku.

Porównanie z

Podprogramy

Podprogramy to szczególne przypadki współprogramów. Gdy podprogramy są wywoływane, wykonanie rozpoczyna się na początku, a gdy podprogram kończy działanie, jest kończony; instancja podprogramu zwraca się tylko raz i nie utrzymuje stanu między wywołaniami. W przeciwieństwie do tego, współprogramy mogą wyjść przez wywołanie innych współprogramów, które mogą później powrócić do punktu, w którym zostały wywołane w oryginalnym współprogramie; z punktu widzenia współprogramu nie jest to wyjście, ale wywołanie innej współprogramu. W ten sposób instancja współprogramowa posiada stan i różni się między wywołaniami; może istnieć wiele wystąpień danego współprogramu naraz. Różnica między wywołaniem innej współprogramu poprzez „poddanie się” a po prostu wywołaniem innej procedury (która wtedy również wróciłaby do pierwotnego punktu), jest taka, że ​​relacja między dwiema współprogramami, które ulegają sobie nawzajem, nie jest relacją wywołującą -callee, ale symetryczne.

Każdy podprogram można przetłumaczyć na współprogram, który nie wywołuje wydajności .

Oto prosty przykład tego, jak przydatne mogą być współprogramy. Załóżmy, że masz relację konsument-producent, w której jedna procedura tworzy elementy i dodaje je do kolejki, a inna usuwa elementy z kolejki i używa ich. Ze względu na wydajność chcesz dodawać i usuwać kilka pozycji jednocześnie. Kod może wyglądać tak:

var q := new queue

coroutine produce
    loop
        while q is not full
            create some new items
            add the items to q
        yield to consume

coroutine consume
    loop
        while q is not empty
            remove some items from q
            use the items
        yield to produce

call produce

Kolejka jest następnie całkowicie wypełniana lub opróżniana przed przekazaniem kontroli innej współprogramie za pomocą polecenia yield . Kolejne wywołania współprogramów zaczynają się zaraz po yield , w zewnętrznej pętli współprogramowej.

Chociaż ten przykład jest często używany jako wprowadzenie do wielowątkowości , dwa wątki nie są do tego potrzebne: instrukcja yield może zostać zaimplementowana przez skok bezpośrednio z jednej procedury do drugiej.

Wątki

Współprogramy są bardzo podobne do wątków . Jednak współprogramy są wielozadaniowe kooperacyjnie , podczas gdy wątki są zazwyczaj wielozadaniowe zapobiegawcze . Współprogramy zapewniają współbieżność, ale nie równoległość . Zaletą współprogramów nad wątkami jest to, że mogą być używane w kontekście twardym w czasie rzeczywistym ( przełączanie między współprogramami nie wymaga żadnych wywołań systemowych ani żadnych wywołań blokujących ), nie ma potrzeby stosowania prymitywów synchronizacji, takich jak muteksy , semafory itp. w celu ochrony krytycznych sekcji i nie ma potrzeby wsparcia ze strony systemu operacyjnego.

Możliwe jest zaimplementowanie współprogramów przy użyciu wątków zaplanowanych z wywłaszczaniem, w sposób, który będzie przezroczysty dla kodu wywołującego, ale niektóre zalety (w szczególności przydatność do pracy w czasie rzeczywistym i względna taniość przełączania się między nimi) zostaną utracone.

Generatory

Generatory, znane również jako semicoroutines, są podzbiorem współprogramów. W szczególności, chociaż oba mogą ustąpić wiele razy, zawieszając ich wykonanie i umożliwiając ponowne wejście w wielu punktach wejścia, różnią się one zdolnością współprogramów do kontrolowania, gdzie wykonanie jest kontynuowane natychmiast po ustąpieniu, podczas gdy generatory nie mogą, zamiast tego przekazują kontrolę z powrotem do wywołującego generatora . Oznacza to, że ponieważ generatory są używane głównie do uproszczenia pisania iteratorów , yieldinstrukcja w generatorze nie określa współprogramu, do którego ma przejść, ale raczej przekazuje wartość z powrotem do procedury nadrzędnej.

Jednak nadal możliwe jest zaimplementowanie współprogramów na szczycie obiektu generatora, za pomocą procedury dyspozytora najwyższego poziomu (w zasadzie trampoliny ), która przekazuje kontrolę bezpośrednio do generatorów podrzędnych identyfikowanych przez tokeny przekazywane z powrotem z generatorów:

var q := new queue

generator produce
    loop
        while q is not full
            create some new items
            add the items to q
        yield consume

generator consume
    loop
        while q is not empty
            remove some items from q
            use the items
        yield produce

subroutine dispatcher
    var d := new dictionary(generatoriterator)
    d[produce] := start produce
    d[consume] := start consume
    var current := produce
    loop
        call current
        current := next d[current]

call dispatcher

Wiele implementacji współprogramów dla języków z obsługą generatora, ale żadne współprogramy natywne (np. Python przed 2.5) używają tego lub podobnego modelu.

Wzajemna rekurencja

Używanie współprogramów dla maszyn stanów lub współbieżności jest podobne do używania wzajemnej rekurencji z wywołaniami ogona , ponieważ w obu przypadkach sterowanie zmienia się na inny zestaw procedur. Jednak współprogramy są bardziej elastyczne i ogólnie bardziej wydajne. Ponieważ współprogramy ustępują, a nie zwracają, a następnie wznawiają wykonywanie, a nie rozpoczynają od początku, są w stanie utrzymać stan, zarówno zmienne (jak w zamknięciu), jak i punkt wykonania, a uzyski nie ograniczają się do położenia ogona; wzajemnie rekurencyjne podprogramy muszą albo używać współdzielonych zmiennych, albo przekazywać stan jako parametry. Co więcej, każde wzajemnie rekurencyjne wywołanie podprogramu wymaga nowej ramki stosu (chyba że zaimplementowano eliminację wywołania końcowego ), podczas gdy przekazywanie kontroli między podprogramami wykorzystuje istniejące konteksty i może być zaimplementowane po prostu przez skok.

Typowe zastosowania

Współprogramy są przydatne do wdrożenia następujących elementów:

  • Maszyny stanowe w ramach pojedynczego podprogramu, gdzie stan jest określany przez bieżący punkt wejścia/wyjścia procedury; może to skutkować bardziej czytelnym kodem w porównaniu z użyciem goto , a także może być zaimplementowane przez wzajemną rekursję z wywołaniami tail .
  • Aktorski model współbieżności, np. w grach wideo . Każdy aktor ma swoje własne procedury (to znowu logicznie oddziela kod), ale dobrowolnie oddają kontrolę centralnemu planerowi, który wykonuje je sekwencyjnie (jest to forma kooperacyjnej wielozadaniowości ).
  • Generatory , a te są przydatne w przypadku strumieni  – w szczególności wejścia/wyjścia – oraz do ogólnego przechodzenia struktur danych.
  • Komunikowanie procesów sekwencyjnych, w których każdy podproces jest współprogramem. Wejścia/wyjścia kanałów i operacje blokujące dają współprogramy, a planista odblokowuje je w przypadku zdarzeń zakończenia. Alternatywnie każdy podproces może być elementem nadrzędnym procesu następującego po nim w potoku danych (lub poprzedzającego go, w którym to przypadku wzorzec może być wyrażony jako generatory zagnieżdżone).
  • Komunikacja odwrotna, powszechnie stosowana w oprogramowaniu matematycznym, w której procedura, taka jak solwer, ewaluator całkowy, ... wymaga użycia procesu do wykonania obliczeń, takich jak ocena równania lub całki.

Wsparcie natywne

Współprogramy powstały jako metoda języka asemblerowego , ale są obsługiwane w niektórych językach programowania wysokiego poziomu .

Ponieważ kontynuacje mogą być używane do implementacji współprogramów, języki programowania, które je obsługują, mogą również dość łatwo obsługiwać współprogramy.

Realizacje

Od 2003 r. wiele z najpopularniejszych języków programowania, w tym C i jego pochodne, nie ma bezpośredniego wsparcia dla współprogramów w języku lub ich standardowych bibliotekach. Wynika to w dużej mierze z ograniczeń implementacji podprogramów opartych na stosie . Wyjątkiem jest biblioteka C++ Boost.Context , część bibliotek boost , która obsługuje zamianę kontekstu na ARM, MIPS, PowerPC, SPARC i x86 na POSIX, Mac OS X i Windows. Współprogramy można budować na Boost.Context.

W sytuacjach, gdy podprogram byłby naturalną implementacją mechanizmu, ale nie jest dostępny, typową reakcją jest użycie domknięcia  – podprogramu ze zmiennymi stanu ( zmienne statyczne , często flagi logiczne) w celu utrzymania wewnętrznego stanu między wywołaniami, a przenieść kontrolę do właściwego punktu. Warunki w kodzie powodują wykonanie różnych ścieżek kodu w kolejnych wywołaniach, na podstawie wartości zmiennych stanu. Inną typową odpowiedzią jest zaimplementowanie jawnego automatu stanów w postaci dużej i złożonej instrukcji switch lub za pomocą instrukcji goto , w szczególności obliczonego goto . Takie wdrożenia są uważane za trudne do zrozumienia i utrzymania oraz stanowią motywację do współprogramowego wsparcia.

Wątki , aw mniejszym stopniu włókna , są dziś alternatywą dla współprogramów w głównych środowiskach programistycznych. Wątki zapewniają narzędzia do zarządzania kooperacyjną interakcją w czasie rzeczywistym przy jednoczesnym wykonywaniu fragmentów kodu. Wątki są szeroko dostępne w środowiskach, które obsługują C (i są obsługiwane natywnie w wielu innych nowoczesnych językach), są znane wielu programistom i zazwyczaj są dobrze zaimplementowane, dobrze udokumentowane i dobrze obsługiwane. Ponieważ jednak rozwiązują duży i trudny problem, zawierają wiele potężnych i skomplikowanych udogodnień i mają odpowiednio trudną krzywą uczenia się. W związku z tym, gdy współprogram jest wszystkim, co jest potrzebne, użycie wątku może być przesadą.

Jedną z ważnych różnic między wątkami a współprogramami jest to, że wątki są zazwyczaj zaplanowane z wyprzedzeniem, podczas gdy współprogramy nie. Ponieważ wątki można zmieniać w dowolnym momencie i mogą być wykonywane jednocześnie, programy używające wątków muszą uważać na blokowanie . W przeciwieństwie do tego, ponieważ współprogramy mogą być zmieniane tylko w określonych punktach programu i nie są wykonywane jednocześnie, programy używające współprogramów często mogą całkowicie uniknąć blokowania. Ta właściwość jest również cytowana jako zaleta programowania sterowanego zdarzeniami lub asynchronicznego.

Ponieważ włókna są uporządkowane wspólnie, stanowią idealną podstawę do wdrożenia powyższych współprogramów. Jednak często brakuje wsparcia systemowego dla włókien w porównaniu z obsługą wątków.

C

Aby zaimplementować współprogramy ogólnego przeznaczenia, należy uzyskać drugi stos wywołań , co jest funkcją nieobsługiwaną bezpośrednio przez język C. Niezawodnym (choć specyficznym dla platformy) sposobem osiągnięcia tego jest użycie niewielkiej ilości zestawu wbudowanego do jawnego manipulowania wskaźnikiem stosu podczas początkowego tworzenia współprogramu. Jest to podejście zalecane przez Toma Duffa w dyskusji na temat jego względnych zalet w porównaniu z metodą stosowaną przez Protothreads . Na platformach, które zapewniają wywołanie systemowe POSIX sigaltstack , drugi stos wywołań można uzyskać przez wywołanie funkcji odskoczni z poziomu obsługi sygnału, aby osiągnąć ten sam cel w przenośnym C, kosztem pewnej dodatkowej złożoności. Biblioteki C zgodne z POSIX lub Single Unix Specification (SUSv3) udostępniały takie procedury jak getcontext, setcontext, makecontext i swapcontext , ale funkcje te zostały uznane za przestarzałe w POSIX 1.2008.

Po uzyskaniu drugiego stosu wywołań za pomocą jednej z metod wymienionych powyżej, funkcje setjmp i longjmp ze standardowej biblioteki C mogą być następnie użyte do zaimplementowania przełączników między współprogramami. Funkcje te zapisują i przywracają odpowiednio wskaźnik stosu , licznik programu , rejestry zapisane przez osoby wywoływane i każdy inny stan wewnętrzny wymagany przez ABI , tak że powrót do współprogramu po ustąpieniu przywraca cały stan, który zostałby przywrócony po powrocie z wywołania funkcji. Minimalistyczne implementacje, które nie wyłączają funkcji setjmp i longjmp, mogą osiągnąć ten sam wynik za pomocą małego bloku wbudowanego asemblera, który zamienia jedynie wskaźnik stosu i licznik programu, a także blokuje wszystkie inne rejestry. Może to być znacznie szybsze, ponieważ setjmp i longjmp muszą konserwatywnie przechowywać wszystkie rejestry, które mogą być używane zgodnie z ABI, podczas gdy metoda clobber pozwala kompilatorowi przechowywać (poprzez rozlanie na stos) tylko tego, o czym wie, że jest faktycznie używany.

Ze względu na brak bezpośredniego wsparcia językowego wielu autorów napisało własne biblioteki dla współprogramów, które ukrywają powyższe szczegóły. Biblioteka libtask Russa Coxa jest dobrym przykładem tego gatunku. Używa funkcji kontekstowych, jeśli są one dostarczane przez natywną bibliotekę C; w przeciwnym razie zapewnia własne implementacje dla ARM, PowerPC, Sparc i x86. Inne godne uwagi implementacje to libpcl, coro, lthread, libCoroutine, libconcurrency, libcoro, ribs2, libdill., libaco i libco.

Oprócz powyższego ogólnego podejścia, podjęto kilka prób aproksymacji współprogramów w C za pomocą kombinacji podprogramów i makr. Wkład Simona Tathama , oparty na urządzeniu Duffa , jest godnym uwagi przykładem gatunku i jest podstawą Protothreads i podobnych implementacji. Oprócz zastrzeżeń Duffa, własne komentarze Tathama dostarczają szczerej oceny ograniczeń tego podejścia: „O ile mi wiadomo, jest to najgorszy fragment hakerstwa C, jaki kiedykolwiek widziano w poważnym kodzie produkcyjnym”. Główne wady tego przybliżenia polegają na tym, że nie utrzymując oddzielnej ramki stosu dla każdego współprogramu, zmienne lokalne nie są zachowywane w wynikach z funkcji, nie jest możliwe posiadanie wielu wpisów do funkcji, a kontrolę można uzyskać tylko z rutyna na najwyższym poziomie.

C++

  • C++20 wprowadził ustandaryzowane współprogramy jako funkcje bez stosu, które można zawiesić w trakcie wykonywania i wznowić w późniejszym momencie. Zawieszony stan współprogramu jest przechowywany na stercie. Wdrażanie tego standardu jest w toku, a kompilatory G++ i MSVC obecnie w pełni obsługują standardowe współprogramy w ostatnich wersjach.
  • Boost.Coroutine - stworzona przez Olivera Kowalke, jest oficjalną wydaną przenośną biblioteką współprogramową boost od wersji 1.53. Biblioteka opiera się na Boost.Context i obsługuje ARM, MIPS, PowerPC, SPARC i X86 na POSIX, Mac OS X i Windows.
  • Boost.Coroutine2 - również stworzony przez Olivera Kowalke, to zmodernizowana przenośna biblioteka współprogramowa od wersji 1.59 boost. Wykorzystuje funkcje C++11, ale usuwa obsługę współprogramów symetrycznych.
  • Mordor - W 2010 roku Mozy udostępnił bibliotekę C++ implementującą współprogramy, z naciskiem na wykorzystanie ich do abstrakcji asynchronicznych operacji we/wy w bardziej znany model sekwencyjny.
  • CO2 - współprogram bez stosu oparty na trikach preprocesora C++ , zapewniający emulację oczekiwania/zysku.
  • ScummVM — projekt ScummVM implementuje lekką wersję współprogramów bez stosu na podstawie artykułu Simona Tathama .
  • tonbit::coroutine - C++11 pojedyncza implementacja asymetrycznej współprogramu .h przez ucontext / fiber
  • Coroutines wylądował w Clang w maju 2017 roku, z trwającą implementacją libc++.
  • elle przez Docker
  • oatpp-coroutines — bez stosu współprogramy z harmonogramem przeznaczone do operacji we/wy o wysokim poziomie współbieżności. Używany w eksperymencie 5 milionów połączeń WebSocket przez Oat++. Część platformy internetowej Oat++ .

C#

  • MindTouch Dream — framework MindTouch Dream REST zapewnia implementację współprogramów opartych na wzorcu iteratora C# 2.0
  • Caliburn — struktura wzorców ekranu Caliburn dla WPF używa iteratorów C# 2,0, aby ułatwić programowanie interfejsu użytkownika, szczególnie w scenariuszach asynchronicznych.
  • Biblioteka Power ThreadingBiblioteka Power Threading firmy Jeffrey Richter implementuje AsyncEnumerator, który zapewnia uproszczony asynchroniczny model programowania przy użyciu współprogramów opartych na iteratorach.
  • Silnik gry Unity implementuje współprogramy.
  • Servelat Pieces - Projekt Servelat kawałki Jewhen Bobrov zapewnia przejrzystą asynchrony Silverlight dla usług WCF i zdolność do asynchronicznie wywołać dowolną metodę synchroniczną. Implementacja jest oparta na iteratorze Coroutines Caliburn i blokach iteratorów C#.
  • [10] — .NET 2.0+ Framework zapewnia teraz funkcjonalność pół-współprogramową ( generator ) za pomocą wzorca iteratora i słowa kluczowego wydajności.

C # 5.0 zawiera czekają na wsparcie składni.

Clojure

Cloroutine to biblioteka innej firmy zapewniająca obsługę współprogramów bez stosu w Clojure . Jest zaimplementowane jako makro, statycznie dzielące dowolny blok kodu na dowolne wywołania var i emitujące współprogram jako funkcję stanową.

D

D implementuje współprogramy jako standardowy generator klasy Fibre A klasy Fibre A , co sprawia, że ​​ujawnienie funkcji światłowodu jako zakresu wejściowego jest trywialne , dzięki czemu każde światłowód jest kompatybilny z istniejącymi algorytmami zakresu.

Jawa

Istnieje kilka implementacji współprogramów w Javie . Pomimo ograniczeń narzuconych przez abstrakcje Javy, JVM nie wyklucza takiej możliwości. Stosowane są cztery ogólne metody, ale dwie psują przenośność kodu bajtowego wśród zgodnych ze standardami maszyn JVM.

  • Zmodyfikowane maszyny JVM. Możliwe jest zbudowanie załatanej maszyny JVM w celu bardziej natywnej obsługi współprogramów. Do maszyny JVM Da Vinci zostały utworzone poprawki.
  • Zmodyfikowany kod bajtowy. Współprogramowa funkcjonalność jest możliwa poprzez przepisanie zwykłego kodu bajtowego Javy, albo w locie, albo w czasie kompilacji. Zestawy narzędzi obejmują Javaflow , Java Coroutines i Coroutines .
  • Mechanizmy JNI specyficzne dla platformy. Wykorzystują one metody JNI zaimplementowane w bibliotekach systemu operacyjnego lub C, aby zapewnić funkcjonalność JVM.
  • Abstrakcje wątków. Biblioteki współprogramowe, które są zaimplementowane przy użyciu wątków, mogą być ciężkie, chociaż wydajność będzie się różnić w zależności od implementacji wątków JVM.

JavaScript

  • włókna węzłowe
    • Fibjs — fibjs to środowisko uruchomieniowe JavaScript zbudowane na silniku JavaScript V8 przeglądarki Chrome. fibjs używa przełączników światłowodowych , stylu synchronizacji i nieblokującego modelu we/wy do budowy skalowalnych systemów.
  • Od ECMAScript 2015 dostępna jest funkcja współprogramu bez stosu za pomocą „generatorów” i wyrażeń wydajności.

Kotlin

Kotlin implementuje współprogramy jako część własnej biblioteki .

Moduł-2

Modula-2 zgodnie z definicją Wirtha implementuje współprogramy jako część standardowej biblioteki SYSTEM.

Procedura NEWPROCESS() wypełnia kontekst mający blok kodu i miejsce na stos jako parametry, a procedura TRANSFER() przekazuje kontrolę do współprogramu, mając jako parametr kontekst współprogramu.

Mononukleoza

Środowisko uruchomieniowe języka wspólnego mono obsługuje kontynuacje, z których można budować współprogramy.

.NET Framework

Podczas opracowywania .NET Framework 2.0 firma Microsoft rozszerzyła projektowanie interfejsów API hosta języka wspólnego języka uruchomieniowego (CLR) do obsługi planowania opartego na światłowodach z myślą o jego użyciu w trybie światłowodowym dla serwera SQL. Przed wydaniem obsługa haka przełączania zadań ICLRTask::SwitchOut została usunięta z powodu ograniczeń czasowych. W związku z tym użycie światłowodowego interfejsu API do przełączania zadań nie jest obecnie realną opcją w .NET Framework.

Perl

Współprogramy są natywnie zaimplementowane we wszystkich backendach Raku .

PHP

  • Amphp
  • Coroutine zaimplementowany w sposób przypominający funkcje Pythona i niektóre Go , wiele przykładów pokazujących tam kod przekonwertowany z taką samą liczbą linii i zachowaniem.

Pyton

  • Python 2.5 implementuje lepsze wsparcie dla funkcjonalności zbliżonej do współprogramu, opartej na rozszerzonych generatorach ( PEP 342 )
  • Python 3.3 poprawia tę zdolność, obsługując delegowanie do podgeneratora ( PEP 380 )
  • Python 3.4 wprowadza kompleksową strukturę asynchronicznego we/wy ustandaryzowaną w PEP 3156 , która zawiera współprogramy wykorzystujące delegowanie podgeneratora
  • Python 3.5 wprowadza wyraźne wsparcie dla współprogram z asynchroniczny / Oczekujcie składni ( PEP 0492 ).
  • Od Pythona 3.7 async/await stały się zastrzeżonymi słowami kluczowymi.
  • Eventlet
  • Greenlet
  • gevent
  • pyton bez stosów

Rubin

Rdza

Rust obsługuje współprogramy od wersji 1.39 . Istnieją dwie popularne biblioteki zapewniające asynchroniczne środowiska wykonawcze: tokio i async-std

Scala

Scala Coroutines to współprogramowa implementacja dla Scala . Ta implementacja jest rozszerzeniem na poziomie biblioteki, które opiera się na systemie makr Scala do statycznego przekształcania części programu w obiekty współprogramowe. Jako taka, ta implementacja nie wymaga modyfikacji w JVM, więc jest w pełni przenośna między różnymi JVM i współpracuje z alternatywnymi backendami Scala, takimi jak Scala.js , który kompiluje się do JavaScript.

Scala Coroutines polega na coroutinemakrze, które przekształca normalny blok kodu w definicję współprogramu. Taką definicję współprogramu można wywołać za pomocą calloperacji, która tworzy instancję ramki współprogramu. Ramkę współprogramową można wznowić za pomocą resumemetody, która wznawia wykonywanie ciała współprogramowego, aż do osiągnięcia yieldvalsłowa kluczowego, które zawiesza ramkę współprogramową. Scala Coroutines ujawnia również snapshotmetodę, która skutecznie powiela współprogram. Szczegółowe opisy współprogramów Scali wraz z migawkami pojawiły się na ECOOP 2018 wraz z ich formalnym modelem .

Schemat

Ponieważ Scheme zapewnia pełne wsparcie dla kontynuacji, implementacja współprogramów jest prawie trywialna, wymagając jedynie utrzymania kolejki kontynuacji.

Pogawędka

Ponieważ w większości środowisk Smalltalk stos wykonawczy jest pierwszorzędnym obywatelem, współprogramy można zaimplementować bez dodatkowej obsługi bibliotek lub maszyn wirtualnych.

Szybki

  • SwiftCoroutine — biblioteka współprogramów Swift dla systemów iOS, macOS i Linux.

Język poleceń narzędzi (Tcl)

Od wersji 8.6, Tool Command Language obsługuje współprogramy w podstawowym języku.

Wala

Vala implementuje natywne wsparcie dla współprogramów. Zostały zaprojektowane do użytku z główną pętlą Gtk, ale mogą być używane samodzielnie, jeśli zadba się o to, aby wywołanie zwrotne nigdy nie musiało być wywoływane przed wykonaniem przynajmniej jednego plonowania.

Języki asemblera

Języki asemblerowe zależne od maszyny często zapewniają bezpośrednie metody wykonywania współprogramów. Na przykład, w MACRO-11 , języku asemblera rodziny minikomputerów PDP-11 , „klasyczny” przełącznik współprogramowy jest wykonywany przez instrukcję „JSR PC,@(SP)+”, która przeskakuje do adresu wyskakującego z stos i odkłada bieżący ( tj. ten z następnego ) adres instrukcji na stos. W VAXen (w VAX MACRO ) porównywalną instrukcją jest "JSB @(SP)+". Nawet na Motoroli 6809 jest instrukcja "JSR [,S++]"; zwróć uwagę na "++", ponieważ 2 bajty (adresu) są usuwane ze stosu. Ta instrukcja jest często używana w (standardowym) „monitor” Assist 09.

Zobacz też

Bibliografia

Dalsza lektura

Zewnętrzne linki