上下文切换执行同一语句两次



我正试图了解上下文切换是如何工作的,以及如何在接收到特定信号后使您的进程切换上下文。这是我的代码

#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 timen", a);
        sleep(5);
        a > 20 ? a = 0 : a++;
    }
}
void thread2_fun() {
    static int a = 1;
    while (1) {
        printf("calling thread2 for %d timen", a);
        sleep(5);
        a > 20 ? a = 0 : a++;
    }
}
void sig_handler(int signal) {
    static int curr_thread = 0;
    printf("received signal %dn", signal);
    if (curr_thread == 1) {
        curr_thread = 0;
        printf("switching from thread1 to thread2n");
        setcontext(&thread1);
    } else {
        curr_thread = 1;
        printf("switching from thread2 to thread1n");    
        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("%dn", getpid());
    while (1);
}

现在我给命令'kill -s SIGUSR1 '从终端。进程在接收到这个信号后切换上下文,但问题是它打印了两次 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

例如,如果thread1打印'调用thread1 第3 时间'并进入睡眠状态,而thread1正在睡觉,如果我发送信号切换上下文,thread2开始执行,现在如果我再次发送信号切换上下文,那么thread1再次打印' em>调用thread1 第3 时间'。理想情况下,它应该从休眠状态中苏醒并增加a的值,对吗?为什么它打印相同的值两次?

下面是代码打印的输出:

接收到信号10

从thread2切换到thread1

调用thread2 1次

接收到信号10

从thread1切换到thread2

调用thread1 1次

接收到信号10

从thread2切换到thread1

调用thread2 1次

接收到信号10

从thread1切换到thread2

调用thread1 1次

请帮帮我。

ucontext_t的uc_link成员虽然是次要的,但是在传递给makecontext之前应该给它赋一个值。

否则,在Linux手册页中,setcontext将调用传递给makecontext的函数。这意味着每次调用setcontext时,不会保存关于thread1_fun或thread2_fun先前执行的信息。这就是为什么同一条消息被多次打印的原因。在前一次调用中,在计数器增加之前,函数处于睡眠状态。在下一次调用时,该函数打印未更改的值。另一方面,Swapcontext将在第一个参数中保存当前上下文,并在第二个参数中激活上下文。

另一件值得注意的事情是信号处理程序在新的上下文中运行。这使得调用setcontext或swapcontext这样的函数有问题。请参阅此处关于swapcontext和信号的讨论。正如在那个链接中所建议的,sig_atomic_t类型的标志可以用于向thread1_fun和thread2_fun中的当前执行状态发出信号,以调用swapcontext。

下面是声明在include下面的新信号变量:

static sig_atmoic_t switch_context = 0;

下面是更新后的thread1_fun (thread2_fun类似于thread1和thread2的交换):

void thread1_fun() {
    static int a = 1;
    while (1) {
        printf("calling thread1 for %d timen", 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 %dn", signal);
    if (curr_thread == 1) {
        curr_thread = 0;
        printf("switching from thread1 to thread2n");
    } else {
        curr_thread = 1;
        printf("switching from thread2 to thread1n");
    }
    switch_context = 1;
}

此外,我在main函数的末尾替换了while (1);,以启动thread1上的上下文。

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

相关内容

  • 没有找到相关文章

最新更新