2016-09-11 2 views
0

컨텍스트 스위칭이 작동하는 방법과 특정 신호를받은 후 프로세스 전환 컨텍스트를 만드는 방법을 배우려고합니다. 여기 내 코드가컨텍스트 스위칭은 동일한 문장을 두 번 실행합니다.

#include<stdio.h> 
#include<stdlib.h> 
#include<ucontext.h> 
#include<signal.h> 
#include<sys/time.h> 
#include<sys/types.h> 
#include<unistd.h> 

#define STACK_SIZE 4096 

static ucontext_t thread1, thread2; 

void thread1_fun() { 
    static int a = 1; 
    while (1) { 
     printf("calling thread1 for %d time\n", a); 
     sleep(5); 
     a > 20 ? a = 0 : a++; 
    } 
} 

void thread2_fun() { 
    static int a = 1; 
    while (1) { 
     printf("calling thread2 for %d time\n", a); 
     sleep(5); 
     a > 20 ? a = 0 : a++; 
    } 
} 

void sig_handler(int signal) { 
    static int curr_thread = 0; 
    printf("received signal %d\n", signal); 
    if (curr_thread == 1) { 
     curr_thread = 0; 
     printf("switching from thread1 to thread2\n"); 
     setcontext(&thread1); 
    } else { 
     curr_thread = 1; 
     printf("switching from thread2 to thread1\n");  
     setcontext(&thread2); 
    } 
} 

int main() { 
    int i = 0; 
    struct sigaction act; 
    act.sa_handler = sig_handler; 
    sigemptyset(&act.sa_mask); 
    act.sa_flags = 0; 
    sigaction(SIGUSR1, &act, NULL); 
    /* sigaction(SIGTERM, &act, NULL); */ 

    getcontext(&thread1); 
    thread1.uc_stack.ss_sp = malloc (STACK_SIZE); 
    thread1.uc_stack.ss_size = STACK_SIZE; 
    thread1.uc_stack.ss_flags = 0; 
    makecontext(&thread1, thread1_fun, 0); 

    getcontext(&thread2); 
    thread2.uc_stack.ss_sp = malloc (STACK_SIZE); 
    thread2.uc_stack.ss_size = STACK_SIZE; 
    thread2.uc_stack.ss_flags = 0; 
    makecontext(&thread2, thread2_fun, 0); 

    printf("%d\n", getpid()); 
    while (1); 
} 

이제 'kill -s SIGUSR1'명령을 터미널에서 제공합니다. 프로세스는이 신호를받은 후 컨텍스트를 전환하지만 문제는 '% d 시간 동안 호출하는 스레드'을 두 번 인쇄한다는 것입니다. 예를 들어

은 thread1 인쇄 ' 3 시간에 대한 thread1 전화'및 절전 모드로 전환하고 난 지금, 실행을 시작 thread2 컨텍스트를 전환하는 신호를 보내면 내가 다시 스위치에 신호를 보내는 경우 thread1 동안 자고 경우 문맥 다음에 thread1은 다시 에 대해 '호출 스레드 1을 인쇄합니다. 시간이'입니다. 이상적으로 그것은 잠에서 나와서 a의 값을 증가시켜야합니다. 같은 값을 두 번 인쇄하는 이유는 무엇입니까?

신호 10

접수

1 시간 thread2 호출 thread1하는

수신 신호 10

thread2로 전환 : 여기

코드에 의해 인쇄 출력 인 thread1에서 thread2로 전환

,451,515,

을 thread2하는 thread1에서 전환 신호 10

접수

1 시간 thread2 호출 thread1하는 thread2로부터 전환 신호 10

수신

1 시간 thread1 호출

전화 걸기 1 (1 시간)

도와주세요.

답변

0

비록 minor이지만 ucontext_t의 uc_link 멤버는 ​​makecontext으로 전달되기 전에 값이 지정되어야합니다.

그렇지 않으면 Linux 매뉴얼 페이지에서 setcontext이 makecontext로 전달 된 함수를 호출합니다. 즉, setcontext가 호출 될 때마다 thread1_fun 또는 thread2_fun의 이전 실행에 대한 정보는 저장되지 않습니다. 이것이 동일한 메시지가 여러 번 인쇄되는 이유입니다. 이전 호출에서 함수는 수면 상태에 있었고 카운터를 증가시킬 수있었습니다. 다음 호출시이 함수는 변경되지 않은 값을 인쇄합니다. 반면에 swapcontext는 첫 번째 인수에 현재 컨텍스트를 저장하고 두 번째 인수에 컨텍스트를 활성화합니다.

또 다른 주목할 점은 신호 처리기가 새로운 컨텍스트에서 실행된다는 것입니다. 따라서 setcontext 또는 swapcontext와 같은 함수를 호출하는 것이 문제가됩니다.swapcontext 및 신호에 대한 설명 here을 참조하십시오. 이 링크에서 제안 된 것처럼 sig_atomic_t 유형의 플래그는 thread1_fun에서 현재 실행 상태로 신호를 보내고 swapcontext를 호출하기 위해 thread2_fun에 신호를 보낼 수 있습니다. 여기

바로 포함 아래에 선언 된 새로운 신호 변수 :

여기
static sig_atmoic_t switch_context = 0; 

업데이트 된 thread1_fun이다 (thread2_fun가 thread1과 thread2와 simlar 인 스위칭) : 여기

void thread1_fun() { 
    static int a = 1; 
    while (1) { 
     printf("calling thread1 for %d time\n", a); 
     sleep(5); 
     a > 20 ? a = 0 : a++; 
     if(switch_context) { 
      switch_context = 0; 
      swapcontext(&thread1, &thread2); 
     } 
    } 
} 

는 새로운 sig_handler :

void sig_handler(int signal) { 
    static int curr_thread = 1; 
    printf("received signal %d\n", signal); 
    if (curr_thread == 1) { 
     curr_thread = 0; 
     printf("switching from thread1 to thread2\n"); 
    } else { 
     curr_thread = 1; 
     printf("switching from thread2 to thread1\n"); 
    } 
    switch_context = 1; 
} 

또한thread1에서 컨텍스트를 시작하는 main 함수의 끝에있는.

ucontext_t main_thread; 
if (swapcontext(&main_thread, &thread1) == -1) { 
    perror("swapcontext"); 
    exit(EXIT_FAILURE); 
} 
return 0; 
관련 문제