Я работал над проектом для курса по операционным системам.Задача состояла в том, чтобы реализовать библиотеку для работы с потоками, похожую на pthreads
, но гораздо более простую.Цель этого состоит в том, чтобы практиковать алгоритмы планирования.Конечный продукт - файл .a
.Курс закончен, и все работает нормально (с точки зрения функциональности).
Хотя мне стало любопытно, с какой проблемой я столкнулся.Например, в трех разных функциях моего исходного файла, если я добавлю следующую строку:
fprintf(stderr, "My lucky number is %d\n", 4);
Я получу ошибку сегментации.То же самое не происходит, если вместо этого используется stdout
, или если форматирование не содержит никаких переменных.
Это оставляет мне два основных вопроса:
Почему это происходит только в трех функциях моего кода, а не в других?
Может ли создание контекстов с использованием getcontext()
и makecontext()
или изменение контекстов с использованиемsetcontext()
или swapcontext()
испортить стандартные файловые дескрипторы?
Моя интуиция говорит, что эти функции могут отвечать за это.Еще больше, если учесть тот факт, что три функции моего кода, в которых это происходит, являются функциями, которые имеют контексты, на которые переключаются другие части кода.Обычно по setcontext()
, хотя swapcontext()
используется для перехода к планировщику, для выбора другого потока для выполнения.
Дополнительно, если это так, то:
Как правильно создавать потоки, используя эти функции?
В настоящее время я делаю следующее:
/*------------------------------------------------------------------------------
Funct: Creates an execution context for the function and arguments passed.
Input: uc -> Pointer where the context will be created.
funct -> Function to be executed in the context.
arg -> Argument to the function.
Return: If the function succeeds, 0 will be returned. Otherwise -1.
------------------------------------------------------------------------------*/
static int create_context(ucontext_t *uc, void *funct, void *arg)
{
if(getcontext(uc) != 0) // Gets a context "model"
{
return -1;
}
stack_t *sp = (stack_t*)malloc(STACK_SIZE); // Stack area for the execution context
if(!sp) // A stack area is mandatory
{
return -1;
}
uc->uc_stack.ss_sp = sp; // Sets stack pointer
uc->uc_stack.ss_size = STACK_SIZE; // Sets stack size
uc->uc_link = &context_end; // Sets the context to go after execution
makecontext(uc, funct, 1, arg); // "Makes everything work" (can't fail)
return 0;
}
Этот код, вероятно, немного изменен, ноизначально это онлайн-пример использования u_context.