2016-09-11 50 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時間'兩次。

例如,如果線程1打印「調用線程1爲時間」,並進入睡眠狀態,雖然線程1,如果我發送信號切換的背景下,線程2開始執行,現在睡着了,如果我再次發送信號至開關然後thread1再次打印'調用thread1爲第3個時間'。理想情況下,它應該從睡眠中出來並增加a的值,正確嗎?爲什麼它打印兩次相同的值?

這裏是由代碼打印輸出:

接收信號10

從線程2切換到線程1

調用線程2 1周時間

接收信號10

從thread1切換到thread2

調用線程1 1周時間

接收信號10

從線程2切換到線程1

調用線程2 1周時間

接收信號10

從線程1切換到線程2

調用thread1 1次

請幫我這個。

回答

0

雖然很小,但ucontext_t的uc_link成員應該在傳遞到makecontext之前分配一個值。

否則,從Linux手冊頁,setcontext將調用傳遞給makecontext的函數。這意味着每次調用setcontext時,都不會保存關於thread1_fun或thread2_fun的先前執行的信息。這就是爲什麼相同的信息打印多次。在之前的調用中,在計數器可以遞增之前,函數處於休眠狀態。在下一次調用時,該函數將打印未改變的值。另一方面,swapcontext會將當前上下文保存在第一個參數中,並在第二個參數中激活上下文。

另一件值得注意的事情是信號處理程序在新的上下文中運行。這使得調用諸如setcontext或swapcontext等函數成爲問題。請參閱有關swapcontext和信號的討論here。正如在該鏈接中所建議的那樣,可以使用sig_atomic_t類型的標誌向thread1_fun和thread2_fun中的當前執行狀態發信號以調用swapcontext。

這裏是正下方的包含聲明的新的信號變量:

static sig_atmoic_t switch_context = 0; 

這裏是更新thread1_fun(thread2_fun是simlar與線程1和線程切換):

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; 
} 

此外,我將while (1);在主函數的末尾啓動thread1的上下文。

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