是否允许跨线程共享上下文(由 ucontext.h
中的函数操作的对象)?也就是说,我可以 swapcontext
将第二个参数作为在另一个线程上的 makecontext
中创建的上下文吗?一个测试程序似乎表明它可以在 Linux 上运行。我找不到关于此的文档,而 Windows 纤程似乎明确支持这样的用例。一般来说,这样做安全吗?这是标准的 POSIX 行为吗?
最佳答案
实际上,有一个 NGPT - linux 的线程库,它使用的不是当前的 1:1 线程模型(每个用户线程是内核线程或 LWP),而是 M:N 线程模型(几个用户线程对应另一个,较少数量的内核线程)。
根据 ftp://ftp.uni-duisburg.de/Linux/NGPT/ngpt-0.9.4.tar.gz/ngpt-0.9.4/pth_sched.c:170 pth_scheduler可以在 native (内核)线程之间移动用户线程上下文:
/*
* See if the thread is unbound...
* Break out and schedule if so...
*/
if (current->boundnative == 0)
break;
/*
* See if the thread is bound to a different native thread...
* Break out and schedule if not...
*/
if (current->boundnative == this_sched->lastrannative)
break;
要保存和恢复用户线程,可以使用ucontext ftp://ftp.uni-duisburg.de/Linux/NGPT/ngpt-0.9.4.tar.gz/ngpt-0.9.4/pth_mctx.c:64似乎这是一种首选方法 (mcsc
):
/*
* save the current machine context
*/
#if PTH_MCTX_MTH(mcsc)
#define pth_mctx_save(mctx) \
( (mctx)->error = errno, \
getcontext(&(mctx)->uc) )
#elif
....
/*
* restore the current machine context
* (at the location of the old context)
*/
#if PTH_MCTX_MTH(mcsc)
#define pth_mctx_restore(mctx) \
( errno = (mctx)->error, \
(void)setcontext(&(mctx)->uc) )
#elif PTH_MCTX_MTH(sjlj)
...
#if PTH_MCTX_MTH(mcsc)
/*
* VARIANT 1: THE STANDARDIZED SVR4/SUSv2 APPROACH
*
* This is the preferred variant, because it uses the standardized
* SVR4/SUSv2 makecontext(2) and friends which is a facility intended
* for user-space context switching. The thread creation therefore is
* straight-foreward.
*/
因此,即使 NGPT 已死且未被使用,它也会选择 *context() 来切换用户线程,甚至在内核线程之间。我假设,在 Linux 上使用 *context() 系列是足够安全的。
将 ucontexts 和其他 native 线程库混合使用时可能会出现一些问题。我会考虑一个 NPTL,它是自 glibc 2.4 以来的标准 linux native 线程库。主要问题是 THREAD_SELF - 指向当前线程的 struct pthread
的指针。 TLS(线程本地存储)也通过 THREAD_SELF 工作。 THREAD_SELF 通常存储在寄存器中( r2 on powerpc 、x86 上的 %gs
等)。 get/setcontext 可能会保存和恢复 native pthread 库的内部破坏寄存器(例如线程本地存储、线程标识等)。
glibc setcontext will not save/restore %gs
register与 pthreads 兼容:
/* Restore the FS segment register. We don't touch the GS register
since it is used for threads. */
movl oFS(%eax), %ecx
movw %cx, %fs
您应该检查一下,setcontext 是否在您感兴趣的架构上保存了 THREAD_SELF 寄存器。此外,您的代码不能在操作系统和 libc
之间移植。
关于linux - 跨线程ucontext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4445220/