setcontext este una dintre funcțiile standard ale bibliotecii POSIX (altele includ getcontext , makecontext și swapcontext ) utilizate pentru a gestiona contextul. Familia setcontextpermite lui C să implementeze modele de proiectare de control al fluxului, cum ar fi iteratoare , fibre și coroutine . Familia poate fi gândită ca o versiune extinsă ; în timp ce acesta din urmă permite doar un singur stack hop non-local, permite crearea de fluxuri de control multiple cooperante cu propriile stive . setjmp/longjmpsetcontext
setcontextdefinit în POSIX .1-2001 și în a doua versiune a specificației UNIX unice , dar nu este disponibil pe toate sistemele de operare asemănătoare UNIX . Funcțiile și tipurile lor asociate sunt definite în fișierul antet ucontext.h . Acestea includ tipul ucontext_tcu care interacționează toate cele patru funcții:
typedef struct ucontext { struct ucontext * uc_link ; sigset_t uc_sigmask ; stack_t uc_stack ; mcontext_t uc_mcontext ; ... } ucontext_t ;uc_linkindică contextul care va fi restabilit la ieșirea din contextul curent dacă contextul a fost creat cu makecontext(context secundar). uc_sigmaskeste folosit pentru a stoca semnalele blocate în context și uc_stackeste stiva utilizată de context. uc_mcontextfolosit pentru a stoca starea de execuție, inclusiv toate registrele CPU , contorul de programe și indicatorul de stivă; mcontext_teste un indicator opac.
De asemenea, sunt definite următoarele funcții:
Exemplul de mai jos arată un iterator implementat cu setcontext. Un astfel de cod este destul de rar; în loc să fie folosite setcontextpentru a implementa multitasking cooperativ, sunt adesea folosite diverse biblioteci de wrapper , de exemplu, GNU Portable Threads .
#include <stdio.h> #include <stdlib.h> #include <ucontext.h> /* Funcția de iterator. Se introduce prima dată când * swapcontext este apelat, apoi se ciclează de la 0 la 9. Fiecare valoare este stocată * i_from_iterator, după care revine la bucla principală folosind swapcontext. * Bucla principală tipărește valoarea și apelează swapcontext pentru a reveni * înapoi la funcție. Când se ajunge la sfârșitul buclei, execuția trece la contextul main_context1*/ buclă goală ( ucontext_t * loop_context , ucontext_t * alt_context , int * i_from_iterator ) { int i ; pentru ( i = 0 ; i < 10 ; ++ i ) { /* Scrieți contorul de bucle în locația de întoarcere a iteratorului. */ * i_from_iterator = i ; /* Stocați contextul buclei în ''loop_context'' și comutați la alt context. */ swapcontext ( bucla_context , alt_context ); } } int main ( void ) { /* Trei contexte: * (1) main_context1 : indică principalul pentru a reveni din buclă. * (2) main_context2 : indică locația comutatorului de context în main * (3) loop_context : indică locul din buclă unde controlul * va sări de la main. */ ucontext_t main_context1 , main_context2 , loop_context ; /* Stivă pentru funcția de iterator. */ char iterator_stack [ SIGSTKSZ ]; /* Flag care indică finalizarea iteratorului. */ volatile int iterator_finished ; /* Valoarea returnată a iteratorului. */ volatile int i_from_iterator ; /* Inițializați contextul iteratorului. uc_link indică spre main_context1, * punctul de întoarcere la sfârșitul iteratorului. */ loop_context . uc_link = & main_context1 ; loop_context . uc_stack . ss_sp = iterator_stack ; loop_context . uc_stack . ss_size = sizeof ( iterator_stack ); getcontext ( & loop_context ); /* Populați loop_context, permițând swapcontext să pornească bucla. * Conversia în (void (*)(void)) este necesară pentru a evita avertismentul * compilatorului și nu afectează comportamentul funcției. */ makecontext ( & loop_context , ( void ( * )( void )) buclă , 3 , & loop_context , & main_context2 , & i_from_iterator ); /* Șterge indicatorul de finalizare. */ iterator_terminat = 0 ; /* Stochează contextul curent în main_context1. Când bucla * se termină, controlul va reveni în acel punct. */ getcontext ( & main_context1 ); dacă ( ! iterator_terminat ) { /* Setați indicatorul iterator_finished pentru a dezactiva repornirea iteratorului. */ iterator_terminat = 1 ; în timp ce ( 1 ) { /* Stocați acest punct în main_context2 și comutați la un iterator. * Primul apel începe bucla, cele ulterioare comută * prin contextul de swap în buclă. */ swapcontext ( & main_context2 , & loop_context ); printf ( "%d \n " , i_from_iterator ); } } returnează 0 ; }Notă: Acest exemplu nu se potrivește cu pagina de referință a specificațiilor [1] . Funcția makecontextnecesită parametri suplimentari să fie de tip int, iar în exemplu, pointerii sunt transferați. Acest lucru poate duce la o eroare pe platformele pe 64 de biți (în special, pe arhitecturile LP64 , unde sizeof(void*) > sizeof(int)). Teoretic, aceste probleme pot fi rezolvate, dar nici aceste soluții nu sunt portabile.