我正试图了解上下文切换是如何工作的,以及如何在接收到特定信号后使您的进程切换上下文。这是我的代码
#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;