- •Раздел 2. Механизмы последовательного выполнения программ
- •2.1. Классификация методов замены контекста
- •2.2. Процедуры как синхронные методы замены контекста
- •2.3. Сопрограммы
- •2.4. Примеры реализации сопрограмм в Си, в защищенном режиме процессора и в Windows
- •2.4.1. Пример реализации сопрограмм в Си
- •2.4.2. Пример реализации сопрограмм в защищенном режиме
- •2.4.3. Пример реализации сопрограмм средствами Windows api
- •2.4.4. Пример реализации сопрограмм средствами ос Linux
- •2.5. Процедуры ос
- •2.6. Прерывания как асинхронный метод замены контекста
- •2.7. Исключения
- •2.7.1. Самая общая характеристика исключений
- •2.7.2 Исключения на низком уровне
- •2.7.3. Исключения в программных средах
2.4.3. Пример реализации сопрограмм средствами Windows api
В Windows API существует средство, называемое Fiber (нить).
Нити могут быть использованы для реализации «сопроцедур», посредствам которых приложение переключается между несколькими взаимосвязанными заданиями.
API нитей включает 6 функций:
ConvertThreadToFiber – включение возможности использовать нити и превращение main-потока в главную нить.
CreateFiber - Создание дополнительных нитей.
GetFiberData – получение данных, сформированных при создании нити.
GetCurrentFiber – получение идентификатора активной нити (собственного идентификатора).
SwitchToFiber – переключение на другую нить.
DeleteFiber – удаление нити.
Нити имеют собственные стеки.
Существует два способа управления нитями:
Управление «ведущий-ведомый», когда все нити передают управление главной нити, а та в свою очередь решает, какой из нитей передать управление.
Равноправное управление, когда сама нить определяет, какая из нитей будет выполняться следующей.
Ниже приведен текст примера, использующего нити Win32.
#include <windows.h>
#include <stdio.h>
#define FIBER_COUNT 3 // total number of fibers (including primary)
#define MAIN_FIBER 0 // array index to main fiber
#define FIRST_FIBER 1 // array index to first fiber
#define SECOND_FIBER 2 // array index to second fiber
LPVOID lpFiber[FIBER_COUNT];
//===================================================================
VOID __stdcall FirstFiberFunc(LPVOID lpParameter) {
int i = 0;
while (1) {
printf("FirstFiberFunc; i = %d\n",i);
i++;
if (i > 11) {
break;
}
SwitchToFiber(lpFiber[SECOND_FIBER]);
}
printf("FirstFiberFunc: return to main fiber\n");
SwitchToFiber(lpFiber[MAIN_FIBER]);
}
//===================================================================
VOID __stdcall SecondFiberFunc(LPVOID lpParameter){
int i = 0;
while (1) {
printf("SecondFiberFunc; i = %d\n",i);
i++;
if (i > 10) {
break;
}
SwitchToFiber(lpFiber[FIRST_FIBER]);
}
printf("SecondFiberFunc: return to main fiber\n");
SwitchToFiber(lpFiber[MAIN_FIBER]);
}
//====================================================================
int __cdecl main(int argc,char *argv[]){
lpFiber[MAIN_FIBER] = ConvertThreadToFiber(NULL);
lpFiber[FIRST_FIBER] = CreateFiber(0, FirstFiberFunc, NULL);
lpFiber[SECOND_FIBER] = CreateFiber(0, SecondFiberFunc, NULL);
SwitchToFiber(lpFiber[FIRST_FIBER]);
DeleteFiber(lpFiber[FIRST_FIBER]);
DeleteFiber(lpFiber[SECOND_FIBER]);
printf("main fiber\n");
return 0;
}
//====================================================================
2.4.4. Пример реализации сопрограмм средствами ос Linux
См. метод. указания к лаб. работам.
Важно!
Этапы создания задач-сопрограмм во всех трех примерах одни и те же. Это:
Выделение памяти под стеки (стек для main выделять не надо);
Выделение памяти под дескрипторы (в том числе и для main);
Необходимым образом выполненная инициализация стеков;
Необходимым образом выполнение инициализации дескрипторов;
Переход из задачи main в одну из сопрограмм;
Переключение сопрограмм по требуемому алгоритму;
Возвращение в задачу main.