Доступны ли контексты (объекты, управляемые функциями в ucontext.h
) по нити? То есть, может ли я swapcontext
со вторым аргументом быть контекстом, созданным в makecontext
в другом потоке? Кажется, что тестовая программа показывает эту работу в Linux. Я не могу найти документацию так или иначе, в то время как волокна Windows явно поддерживают такой вариант использования. Это безопасно и нормально делать вообще? Это стандартное поведение POSIX, которое должно работать?
Ucontext по потокам
Ответ 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: хотя это обсуждение, кажется, указывает, что вы не должны смешивать их.