linux - 跨线程ucontext

标签 linux coroutine

是否允许跨线程共享上下文(由 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/

相关文章:

linux - 带有连续管道的 grep 不起作用

android - 在挂起函数上调用 await() 无法正常工作

AndroidNetworking 在 Kotlin 中的 suspendCoroutine 中永远不会返回

linux - wc -m in linux excess 1 值

将共享库编译成程序?

c++ - 协程和带有静态变量的函数有什么区别?

unit-testing - 使用 kotlin 协程时,如何对调用挂起函数的函数进行单元测试?

c# - 在 Unity Coroutine 中等待事件?

linux - 如何在 freebsd 的不同 session 中执行子进程

c - 我如何在 Linux 上用 C 语言获取我的 IP 地址?