Информация Да что вы знаете о волокнах?

Receiver

leet-cheats 👑
Автор темы
Модератор
637
942
Привет! Поговорим сегодня о волокнах (fibers) в Windows. Да что вы знаете о волокнах? Кто-нибудь вообще о них слышал? Оказывается слышал. Поэтому начнём обо всём по порядку.

Что из себя представляет волокно?

Вырезка из MSDN:
Волокно — это единица выполнения, которую приложение должно запланировать вручную. Волокна выполняются в контексте потоков, которые планируют их. Каждый поток может запланировать несколько волокон. Как правило, волокна не предоставляют преимуществ по сравнению с хорошо спроектированными многопоточных приложений. Однако использование волокон может упростить перенос приложений, предназначенных для планирования собственных потоков.
Если говорить на языке фактов, то волокно это управляемый поток. Механизмом работы волокна не отличается от потока. Они не выигрывают по производительности, но зато дают одно важное преимущество пользователю — возможность управления. При этом сами волокна подчиняются потокам, ведь по время их работы Windows продолжает планировать потоки. При переключении с потока выполняющего Fiber на другой его выполнение так же будет приостановлено и продолжиться лишь при обратном переключении.

Как работать с волокном?

Первое что мы должны сделать так это конвертировать поток в волокно:
C++:
// Конвертирует текущий поток в волокно
// Возвращает очень важное значение LPVOID - адрес созданного волокна
// Его нужно хранить для последующих переключений
LPVOID ConvertThreadToFiber(
  [in, optional] LPVOID lpParameter
);

// Этой функцией можно получить данные переданные
// волокну в lpParameter, если такие есть
PVOID GetFiberData();
После нам нужно будет создать второе волокно. Создавать волокна мы можем только из волокон, поэтому мы конвертировали поток.
C++:
// Создаёт новое волокно из уже существующего
// Так же возвращает адрес волокна требующий сохранения
LPVOID CreateFiber(
  [in]           SIZE_T                dwStackSize, // рамзер стека (можно ставить 0)
  [in]           LPFIBER_START_ROUTINE lpStartAddress, // вызываемая функция
  [in, optional] LPVOID                lpParameter
);
// lpParameter точно так же можно получить внутри волокна через GetFiberData
Теперь уже можно заниматься их переключением и делается это очень просто:
C++:
// Переключает текущее волокно
void SwitchToFiber(
  [in] LPVOID lpFiber // адрес волокна на которое нужно переключиться
);
Помимо прочего мы можем получить адрес текущего волокна:
C++:
// Возвращает адрес текущего волокна
PVOID GetCurrentFiber();
Это может пригодиться наверное лишь для проверок, чтобы не допустить рекурсии.

Как волокна хранят данные?


Волокнам точно так же как и потокам нужно хранить принадлежащие им статические данные. Поэтому для этого используется абсолютно идентичный потокам механизм, за исключением изменения одной буквы в аббревиатуре — FLS (Fiber Local Storage). Текущий FLS переключается как при изменении самого волокна, так и управляющего им потока. Управлять этой структурой можно с помощью следующих функций:
C++:
// Если указан FLS Callback, то вызывается при: удалении волокна, выходе потока, удалении FLS
PFLS_CALLBACK_FUNCTION PflsCallbackFunction;

void PflsCallbackFunction(
  [in] PVOID lpFlsData
)

// Создаёт FLS возвращаего его индекс.
DWORD FlsAlloc(
  [in] PFLS_CALLBACK_FUNCTION lpCallback
);

// Возвращает значение по индексу FLS
PVOID FlsGetValue(
  [in] DWORD dwFlsIndex
);

// Устанавливает значение по индексу FLS
BOOL FlsSetValue(
  [in]           DWORD dwFlsIndex,
  [in, optional] PVOID lpFlsData
);

// Удаляет FLS
BOOL FlsFree(
  [in] DWORD dwFlsIndex
);

И зачем в итоге это всё нужно?

С помощью этой дичи мы можем очень легко склепать самопальный менеджер короутин позволяющий вручную управлять выполнением программы и при этом не бояться гонки данных, но только при однопоточной работе приложения! Я уже занимался подобным 22-м году, так что можете ознакомиться: https://www.blast.hk/threads/118982/. Только скажу что на практике это бесполезно, потому что никакого выигрыша по времени не даёт, к тому же сам Microsoft говорит что волокна может лишь упростить перенос приложений. Поэтому всем заинтересованным в короутинах порекомендовал бы использовать asio.