콘텍스트 설정

setcontext

setcontext는 컨텍스트 제어에 사용되는 Clibrary 함수 패밀리(getcontext, makecontextswapcontext) 중 하나입니다.setcontext family를 사용하면 반복기, 파이버, Coroutine 등의 고급 제어 흐름 패턴을 C에 구현할 수 있습니다.setjmp/longjmp의 확장 버전으로 볼 수 있지만, setjmp/longjmp에서는 로컬이 아닌1개의 점프만 허용됩니다.setcontext 를 사용하면 각각 자체 스택을 가진 여러 의 공동 스레드 제어가 가능합니다.

사양

setcontext 는 POSIX.1-2001 및 Single Unix Specification, version 2 에 지정되어 있습니다만, 모든 Unix 계열의 operating system이 이러한 기능을 제공하는 것은 아닙니다.POSIX.1-2004 에서는 이러한 기능이 폐지되어 POSIX.1-2008에서는 POSIX 스레드가 대체 가능한 으로서 삭제되었습니다.IEEE 규격 1003.1, 2004년판 인용:[1]

ISO/IEC 9899:1999 표준을 이 규격에 통합함에 따라 ISO C 표준(하위 절 6.11.6)은 빈 괄호가 있는 기능 선언자의 사용을 청소년기의 특징으로 규정하는 것으로 밝혀졌다.따라서 기능 프로토타입을 사용하여 다음을 수행합니다.

void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);

ISO C 표준의 사춘기적 특징을 이용하고 있습니다.따라서 엄밀하게 준거한 POSIX 어플리케이션에서는 이 폼을 사용할 수 없습니다.따라서 getcontext(), makecontext() 및 swapcontext()의 사용은 objective로 표시됩니다.

ISO C 표준에서는 함수를 임의의 타입(정수, 데이터에 대한 포인터, 함수에 대한 포인터 및 복합 타입 포함)의 인수로 임의의 수(0 포함)로 호출하는 것을 나타내는 비 사춘기 함수 프로토타입을 지정할 수 없습니다.

정의들

기능 및 관련 유형은 에 정의되어 있습니다.ucontext.h시스템 헤더 파일여기에는ucontext_t4가지 기능이 모두 작동하는 유형:

유형화된 구조 {  콘텍스트_t *uc_link;  sigset_t    uc_masksmask;  스택_t     uc_stack;  콘텍스트_t  uc_mcontext;  ... } 콘텍스트_t; 

uc_link현재 콘텍스트가 종료되었을 때 재개되는 콘텍스트를 가리킵니다.makecontext(세컨더리 컨텍스트). uc_sigmask는 컨텍스트에서 차단된 신호 세트를 저장하기 위해 사용됩니다.uc_stack는 컨텍스트에서 사용되는 스택입니다. uc_mcontext 는 모든 레지스터와 CPU 플래그, 명령 포인터 및 스택포인터를 포함한 실행 스테이트를 저장합니다.mcontext_t불투명한 타입입니다.

기능은 다음과 같습니다.

  • int setcontext(const ucontext_t *ucp)
    이 함수는 의 컨텍스트에 제어를 전송합니다.ucp. 컨텍스트가 저장된 시점부터 실행이 계속됩니다.ucp.setcontext는 돌아오지 않습니다.
  • int getcontext(ucontext_t *ucp)
    현재 콘텍스트를 저장합니다.ucp이 함수는 첫 번째 호출 후 또는 스레드가 의 컨텍스트로 전환될 때 두 가지 경우에 반환됩니다.ucp경유로setcontext또는swapcontext.그getcontext함수는 케이스를 구별하기 위한 반환값을 제공하지 않습니다(그 반환값은 신호 오류에만 사용됩니다).따라서 프로그래머는 명시적 플래그 변수를 사용해야 합니다.이것은 레지스터 변수가 아니어야 하며 지속적인 전파다른 컴파일러 최적화를 피하기 위해 휘발성으로 선언되어야 합니다.
  • void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
    makecontext함수는 대체 제어 스레드를 설정한다.ucp를 사용하여 이미 초기화되어 있습니다.getcontext.그ucp.uc_stack구성원은 적절한 크기의 스택을 가리켜야 합니다.상수SIGSTKSZ는 일반적으로 사용됩니다.언제ucp바로 사용할 수 있습니다.setcontext또는swapcontext에 의해 지시된 함수의 엔트리 포인트에서 실행이 시작됩니다.func,와 함께argc지정된 대로 인수를 지정합니다.언제func종료, 제어가 에 반환됩니다.ucp.uc_link.
  • int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
    제어의 이전처ucp현재 실행 상태를 저장합니다.oucp.

다음 예시는 반복기에서 다음을 사용하는 방법을 보여 줍니다.setcontext.

#실패하다 <stdio.h> #실패하다 <stdlib.h> #실패하다 <콘텍스트>h> #실패하다 <고객명>님.h>  /* 3가지 컨텍스트: * (1) main_context1 : 루프가 돌아오는 메인 포인트. * (2) main_context2 : 루프로부터의 제어가 이루어지는 메인 포인트 * 콘텍스트 전환에 의한 흐름. * (3) loop_context : 메인으로부터의 제어가 루프의 포인트 * 콘텍스트 전환에 의한 흐름.*/ 콘텍스트_t main_main1, main_param2, loop_module;  /* 반복기 반환값입니다.*/ 휘발성의 인트 i_from_iterator;  /* 이것은 반복기 기능입니다.첫 번째 호출 시 입력됩니다. * swapcontext 및 루프 범위는 0 ~9 입니다.각 값은 i_from_iterator에 저장됩니다. * 다음으로 메인루프로 돌아가기 위해 swapcontext를 사용합니다.메인 루프가 인쇄됩니다. * 값을 호출하여 swapcontext를 호출하여 함수로 되돌립니다.끝날 때 루프의 *에 도달하여 함수가 종료되고 실행이 * main_context1이 가리키는 컨텍스트.*/ 무효 고리(     콘텍스트_t *loop_module,     콘텍스트_t *other_module(기타_module),     인트 *i_from_iterator) {     인트 i;          위해서 (i=0; i < > 10; ++i) {         /* 루프 카운터를 반복기 반환 위치에 씁니다.*/         *i_from_iterator = i;                  /* 루프 컨텍스트(코드의 이 포인트)를 "loop_context"에 저장합니다. * 및 other_switch로 전환합니다.*/         콘텍스트를 교환하다(loop_module, other_module(기타_module));     }          /* 함수는 발신 컨텍스트에 암묵적으로 접속되어 있습니다. * "setcontext(&loop_context->uc_link)";" */ }    인트 주된(무효) {     /* 반복기 기능의 스택.*/      리터레이터_스택[신호];      /* 반복이 완료되었음을 나타내는 플래그.*/     휘발성의 인트 리터레이터_개요;      콘텍스트를 취득하다(&loop_module);     /* 반복기 컨텍스트를 초기화합니다.uc_link는 main_link1, * 반복기 종료 시점으로 돌아갑니다.*/     loop_module.uc_link          = &main_main1;     loop_module.uc_stack.ss_sp   = 리터레이터_스택;     loop_module.uc_stack.ss_size = 크기(리터레이터_스택);      /* swapcontext start loop이 되도록 loop_context를 입력합니다. * ( ( ( ( ( ( ) ) typecast )는 컴파일러의 경고를 피하기 위한 것입니다만, 이것은 * 기능의 동작과는 관련이 없습니다.*/     콘텍스트를 작성하다(&loop_module, (무효 (*)(무효)) 고리,         3, &loop_module, &main_param2, &i_from_iterator);         /* 완료된 플래그를 지웁니다.*/           리터레이터_개요 = 0;      /* 현재 콘텍스트를 main_context1에 저장합니다.루프가 끝나면 * 제어 흐름은 이 지점으로 돌아갑니다.*/     콘텍스트를 취득하다(&main_main1);        한다면 (!리터레이터_개요) {         /* 이전 getcontext가 다음과 같이 되도록 iterator_finished를 설정합니다. * uc_link 경유로 에 반환됩니다.상기의 조건이 false일 경우, * 반복기는 재시작되지 않습니다.*/         리터레이터_개요 = 1;                 하는 동안에 (1) {             /* 이 포인트를 main_context2에 저장하고 반복기로 전환합니다. * 첫 번째 콜은 루프를 시작합니다.후속 콜은 로 전환됩니다. * 스왑 컨텍스트가 루프 상태입니다.*/             콘텍스트를 교환하다(&main_param2, &loop_module);             인쇄물(%d\n", i_from_iterator);         }     }          돌아가다 0; } 

메모: 이 예는 [1]올바르지 않지만 경우에 따라서는 올바르게 동작할 수 있습니다.함수makecontext유형을 지정할 추가 매개 변수가 필요합니다.int단, 이 예에서는 포인터를 전달합니다.따라서 64비트 머신(특히 LP64 아키텍처)에서는 이 경우)에서 실패할 수 있습니다.sizeof(void*) > sizeof(int)이 문제는 64비트 값을 분할하여 재구성함으로써 해결할 수 있지만 이로 인해 성능 저하가 발생합니다.

int 타입과 포인터 타입이 같은 크기(예를 들어 x86-32)인 아키텍처에서는 argc 뒤에 makecontext()를 인수로서 건네주는 포인터를 회피할 수 있습니다.그러나, 이것을 하는 것은, 이식 가능한 것을 보증하는 것은 아니고, 표준에 따라서 정의되어 있지 않으며, 포인터가 ints보다 큰 아키텍처에서는 동작하지 않습니다.단, 버전 2.8 이후 glibc는 일부 64비트아키텍처(x86-64 등)에서 이를 허용하기 위해 에 몇 가지 변경을 가했습니다.


get 콘텍스트 및 set 콘텍스트의 경우 작은 콘텍스트가 편리합니다.

#실패하다 <stdio.h> #실패하다 <콘텍스트>h> #실패하다 <리스트 없음.h>  인트 주된(인트 argc, 컨스턴트  *argv[]){  콘텍스트_t 맥락;    콘텍스트를 취득하다(&맥락);  놓다('헬로 월드');  수면.(1);  콘텍스트 설정(&맥락);  돌아가다 0; } 

컨텍스트가 프로그램카운터를 유지하기 때문에 무한 루프가 됩니다.

레퍼런스

  1. ^ a b 오픈 그룹 베이스 사양 제6호 IEEE 규격 1003.1, 2004년판 [1]

외부 링크