提问人:An Assembler 提问时间:11/10/2023 最后编辑:ikegamiAn Assembler 更新时间:11/10/2023 访问量:48
C - 切换上下文并将旧文件存储在队列中
C - Switch Context and Store Old in Queue
问:
我正在尝试使用该库在 c 中实现线程切换器。ucontext.h
我使用队列系统执行此操作,其中要运行的下一个线程位于队列的前面。当线程暂停时;我弹出队列顶部的节点,将正在运行的上下文与存储在该节点中的上下文切换,然后将该节点推回队列。这看起来像这样:
我有一个测试用例,我在队列中放置了两个线程。每个线程在暂停之前打印其 ID。我希望两者交替出现。相反,第一个线程运行到完成,第二个线程不运行。我已将此问题缩小到交换线程的方式:
QManager.c网站
void pause () {
struct ThreadNode* t= QManagerPop(Q);
swapcontext(t->context, t->context);
QManagerPush(t);
}
看似;这不会将正在运行的上下文与存储在“t->context”中的上下文切换。
我正在寻找一种方法来做到这一点;将当前上下文放在变量“t->context”中,同时恢复存储在该变量中的上下文。
我根据在网上找到的一些信息尝试了以下方法
QManager.c网站
void switch (ucontext_t* c) {
volatile int isSwap = 0;
int isGet = getcontext(c);
if (!isSwap && isGet ==0) {
isSwap = 1;
setcontext(c);
}
}
void pause () {
struct ThreadNode* t= QManagerPop(Q);
switch(t->context);
QManagerPush(t);
}
这将产生相同的行为(末尾有一个额外的段错误)。
有没有办法做我想做的事情?也许是带有临时变量的东西?当上下文切换时,我将如何处理此变量?
答:
0赞
An Assembler
11/10/2023
#1
好吧,我解决了我的问题。感谢@ikegami指出我不能使用相同的参数调用 swapcontext,也不能期望函数在交换后推送。我的代码现在看起来像
void pause () {
struct ThreadNode* t= QManagerPop(Q);
struct ThreadNode* s= malloc(sizeof(struct ThreadNode));
s -> context = malloc(sizeof(ucontext_t));
QManagerPush(s);
swapcontext(QManagerTail(Q)->context, t->context);
}
评论
0赞
ikegami
11/10/2023
你永远不会自由和.t
t->context
0赞
ikegami
11/10/2023
#2
- 上下文的两个参数不能是同一个指针,因为参数是 .
swapcontext
restrict
- 交换后,无法将旧上下文推送到队列中。该“线程”不再执行!它需要在交换之前完成。
您可以使用线程 ID,而不是分配和取消分配所有这些线程,也就是说,索引到包含线程的上下文和其他数据的结构数组中。
然后,切换上下文上下文变为
void switch_to_thread( ThreadId new_thread_id ) {
ThreadId old_thread_id = current_thread_id;
current_thread_id = new_thread_id;
swapcontext(
&( threads[ old_thread_id ].context ),
&( threads[ new_thread_id ].context )
);
}
并成为pause
void yield( void ) {
QManagerEnqueue( q, current_thread_id );
ThreadId new_thread_id = QManagerDequeue( q );
switch_to_thread( new_thread_id );
}
实际上,如果所有线程都在一个数组中,那么我们就不需要队列。我们只需要找到数组中的下一个线程。
ThreadId get_next_thread( void ) {
ThreadId thread_id = current_thread_id;
while ( 1 ) {
thread_id = ( thread_id + 1 ) % MAX_THREADS;
int state = threads[ thread_id ].state;
if ( state == STATE_CREATED || state == STATE_RUNNING )
return thread_id;
}
}
void yield( void ) {
switch_to_thread( get_next_thread() );
}
这段代码来自我之前的回答,您可以在其中看到这些函数的使用。
请注意以下修复:
void f()
并不意味着该函数不带参数。
请注意以下重命名:
Q
⇒ .
它不是模块名称或常量。q
QManagerPush
⇒和
⇒。
Push 和 pop 是堆栈操作,而不是队列操作。QManagerEnqueue
QManagerPop
QManagerDequeue
pause
⇒ .
或者是更合适的名称。yield
yield
cede
评论
swapcontext
swapcontext
QManagerPush(t)
swapcontext
restrict
ucontext_t