Если вы действительно хотите сделать что-то вроде того, что позволяют функции ucontext.h
, я бы продолжил их использовать.Все остальное будет менее переносимым.Помечать их как устаревшие в POSIX кажется ужасной ошибкой педантизма кем-то из членов комитета.Сам POSIX требует, чтобы указатели функций и указатели данных были одинакового размера, а указатели функций должны быть представимо приведенными к void *
, а сам C требует приведения между типами указателей на функции и обратно, чтобы быть безопасным в обоих направлениях, поэтому существует много способовэта проблема могла быть решена.
Существует одна реальная проблема, заключающаяся в том, что преобразование int argc, ...
, переданного в makecontext
, в форму для передачи в функцию не может быть выполнено без серьезной помощи компилятора, если только вызовСоглашение для функций с переменными и не переменными оказывается одинаковым (и даже тогда весьма сомнительно, может ли это быть сделано надежно).Эта проблема, однако, могла бы быть решена просто путем отказа от использования makecontext
в любой форме, отличной от makecontext(ucp, func, 1, (void *)arg);
.
Возможно, лучший вопрос, однако, почему вы думаете, что функции ucontext.h
являются лучшим способом обработкирезьб.Если вы хотите пойти с ними, я мог бы предложить написать интерфейс-обертку, который вы можете реализовать или с ucontext.h
или с pthreads, а затем сравнить производительность и раздувание.Это также будет иметь то преимущество, что, если в будущих системах будет отсутствовать поддержка ucontext.h
, вы можете просто переключиться на компиляцию с реализацией на основе pthread, и все будет просто работать.(К тому времени, раздувание может быть менее важным, выгода многоядерности / SMP, вероятно, будет огромной, и, надеюсь, реализации pthread будут менее раздутыми.)
Редактировать (основано наЗапрос OP): Для реализации "кооперативной потоковой обработки" с помощью pthreads вам нужны переменные условия.Вот приличное руководство по pthreads с информацией об их использовании:
https://computing.llnl.gov/tutorials/pthreads/#ConditionVariables
Ваш примитив многозадачности "Передача выполнения потоку X" будет выглядеть примерно так:
self->flag = 0;
other_thread->flag = 1;
pthread_mutex_lock(other_thread->mutex);
pthread_cond_signal(other_thread->cond);
pthread_mutex_unlock(other_thread->mutex);
pthread_mutex_lock(self->mutex);
while (!self->flag)
pthread_cond_wait(self->cond, self->mutex);
pthread_mutex_unlock(self->mutex);
Надеюсь, я все понял;по крайней мере, общая идея верна.Если кто-то видит ошибки, пожалуйста, прокомментируйте, чтобы я мог это исправить.Половина блокировки (мьютекс other_thread
), вероятно, совершенно не нужна при таком использовании, так что вы могли бы сделать мьютекс локальной переменной в функции task_switch
.Все, что вы действительно будете делать - это использовать pthread_cond_wait
и pthread_cond_signal
в качестве примитивов "идти спать" и "пробуждать другие потоки".