Ucontext по потокам

Доступны ли контексты (объекты, управляемые функциями в ucontext.h) по нити? То есть, может ли я swapcontext со вторым аргументом быть контекстом, созданным в makecontext в другом потоке? Кажется, что тестовая программа показывает эту работу в Linux. Я не могу найти документацию так или иначе, в то время как волокна Windows явно поддерживают такой вариант использования. Это безопасно и нормально делать вообще? Это стандартное поведение POSIX, которое должно работать?

Ответ 1

На самом деле, была библиотека 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 (kernel):

        /*
         * 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() для переключения пользовательских потоков даже между потоками ядра. Я предполагаю, что использование семейства * context() достаточно безопасно для Linux.

При смешивании ucontexts и другой собственной библиотеки потоков могут возникать проблемы. Я рассмотрю NPTL, который является стандартной библиотекой потоковых потоков linux с glibc 2.4. Основной проблемой является THREAD_SELF - указатель на struct pthread текущего потока. TLS (локальное хранилище потоков) также работает через THREAD_SELF. THREAD_SELF обычно хранится в регистре (r2 на powerpc, %gs на x86 и т.д.). get/setcontext может сохранять и восстанавливать этот регистр, разбивая внутренние компоненты собственной библиотеки pthread (например, локальное хранилище потоков, идентификация потоков и т.д.).

. glibc setcontext не будет сохранять/восстанавливать %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 s.

Ответ 2

На странице

В системной V-подобной среде один имеет тип ucontext_t, определенный в  и четыре функции getcontext (2), setcontext (2), makecontext() и swapcontext(), которые разрешить переключение контекста на уровне пользователя между несколькими потоками управления в рамках процесса.

Звучит так, как это.

EDIT: хотя это обсуждение, кажется, указывает, что вы не должны смешивать их.