Почему реализация потока пользовательского уровня (волокна) требует нового выделенного стека для каждого волокна?

В C волокна могут быть закодированы с помощью setjmp() а также longjmp() реализовать переключение контекста на уровне пользователя.
Как описано в evanjones.ca и Portable Multithreading (pdf), также необходимо, чтобы каждое волокно имело вновь выделенный стек.
Так как волокно живет в контексте потока, при его вызове автоматически будет связан кадр стека, так зачем ему нужен этот новый выделенный стек?: когда волокно хочет переключиться на другое, можно использовать следующий подход:

 cpu_context[N] :global array where the i-th entry is the cpu context(jmp_buffer) of the i-th fiber 

fiber_ith :
   [...]
   if ( setjmp(cpu_context[i]) == 0 ){
        longjmp(cpu_context[j])
   }
   [...]

Необходимость нового стека связана с тем, что, как написано здесь, невозможно использовать longjmp() вернуться к выполнению волокна, кадр стека которого больше не действителен с момента вызова волокна longjmp()?

РЕДАКТИРОВАТЬ: эти волокна не должны быть преждевременными и могут добровольно переключаться с одного волокна на другое

2 ответа

Решение

Предположим, что у волокна есть функция, которая вызывает другую функцию, которая вызывает другую функцию, которая затем вызывает переключение этого волокна на другое волокно. Когда мы возобновляем это волокно, нам нужно убедиться, что все локальные переменные вернулись так же, как и при переключении волокна, и мы должны убедиться, что возврат из этой функции возвращается к вызывающей функции. Таким образом, появляются следующие правила:

  1. Пока работает волокно, оно может изменить свой стек.
  2. Когда оптоволокно возобновляется, стек должен вернуться туда, где он был, когда оптоволокно было переключено.

Из этих двух правил немедленно следует, что каждое волокно должно иметь свой собственный стек.

Во-первых, потоки не предназначены для ручного управления собственной диспетчеризацией. То есть не предполагается, что поток решит завершить или приостановить свое выполнение и запустить другой поток. Скорее, потоки доступны для одновременного запуска, и система может запускать несколько потоков на разных физических или виртуальных процессорах одновременно или может запускать и останавливать потоки, чтобы они совместно использовали доступное время на процессоре.

Поскольку потоки могут выполняться одновременно, они должны иметь отдельные стеки. Каждый поток будет изменять и использовать свой собственный стек, возможно, одновременно с тем, как другие потоки изменяют и используют свои. Эти стеки должны быть отдельными, чтобы избежать конфликтов.

Во-вторых, setjmp а также longjmp не предназначены для перехода к произвольным точкам в состоянии потока. Программа может использовать longjmp только чтобы вернуться к предыдущему setjmp в его текущем стеке вызовов, в том же потоке. Вы не могли бы, например, сделать какую-то работу, помните состояние A с setjmp, сделайте еще немного работы, запомните состояние B с setjmp, затем longjmp заявить A, и позже longjmp заявить B, После longjmp в A, B больше недоступно - все, что было сохранено для него setjmp больше не действителен

Другие вопросы по тегам