【发布时间】:2015-09-11 19:29:25
【问题描述】:
我正在为一个大学项目编写一个使用上下文切换的简单线程库。我在从线程执行返回时遇到问题。
最初我切换到一个新创建的线程是这样的:
int done = 0;
getcontext(&parent_context);
if (!done) {
done = 1;
setcontext(&(thread->context));
}
return thread->tid;
其中thread->context.uc_link 是&parent_context。它可以工作,但我需要在创建线程时调用调度程序,而不是仅仅切换到它的上下文。所以我将thread->context.uc_link 设置为NULL 而不是&parent_context 并将上面的代码替换为
schedule(thread);
scheduler();
return thread->tid;
其中schedule 将线程入队,scheduler 获取队列中的第一个线程并调用dispatcher,这只是对setcontext 的调用。问题是,我需要线程将控制权返回给调度程序。我发生的第一件事是:
static void
scheduler()
{
int dispatched = 0;
ucontext_t ret;
// Get the first thread in the queue, then
thread->context.uc_link = &ret;
getcontext(&ret);
if (!dispatched) {
dispatched = 1;
setcontext(&(thread->context));
}
// Remove the dispatched thread from the queue
}
这不起作用 - 线程不会将控制权返回给调度程序,并且程序会在线程终止执行后结束。我认为这是因为我在更改uc_link 后没有调用makecontext。但是,为了调用makecontext,我必须将线程的函数指针和参数传递给调度程序,这是不可取的,因为我无法修改线程数据结构来存储它(项目规则)。我在网上找到的使用上下文切换的线程“库”在线程函数内调用setcontext:
http://www.evanjones.ca/software/threading.html
http://nitish712.blogspot.com.br/2012/10/thread-library-using-context-switching.html
这也是不可取的,因为用户不需要自己进行上下文切换。如何使线程将控制权返回给调度程序?我能想到的一种技巧是使用静态变量ucontext_t return_context 并将其用作所有线程的uc_link。因此,在调用调度程序之前,我会执行getcontext(&return_context),调度程序变为:
// Get the first thread in the queue, then
// Remove the thread from the queue
setcontext(&(thread->context));
这似乎可行,但这样没有两个线程可以同时执行。这不是这个项目的问题,但它似乎是错误的。另一个问题是调用调度程序的每个函数都充当调度程序:
int done = 0;
getcontext(&return_context);
if (!done) {
done = 1;
scheduler();
}
fprintf(stderr, "Thread returned\n");
这是要走的路吗?
【问题讨论】:
-
我认为不可能在用户空间中实现并行线程。 evanjones.ca 链接提到了纤程,它们通常是协作异步的,而不是并行的。
-
通过上下文switching实现线程的起始前提意味着您将执行CPU切片,而不是并发多线程。两个线程不需要上下文切换即可在不同的内核上同时运行。
-
尽管如此,您的库也许可以在多个并行操作系统线程的上下文中运行。我认为您无法在线程之间传输上下文,但如果您小心避免全局数据,那么您可以在线程内执行切片。如果您可能需要全局数据,请考虑使用线程本地数据。