uIP 1.0
|
Протопотоки - это тип облегченных потоков без использования стека, разработанный для систем с малым количеством памяти, таких как встраиваемые (embedded) системы на микроконтролллерах или сетевые узлы датчиков. Подробнее...
Группы | |
Локальные продолжения (Local continuations, далее LC) | |
LC являются базой для реализации протопотоков. | |
Файлы | |
файл | pt.h |
Реализация protothread-ов. | |
Initialization | |
#define | PT_INIT(pt) |
Инициализация protothread. | |
Декларация и определение | |
#define | PT_THREAD(name_args) |
Декларация protothread. | |
#define | PT_BEGIN(pt) |
Декларирует начало protothread внутри функции C, реализующей protothread. | |
#define | PT_END(pt) |
Декларируется конец для protothread. | |
Блокирующее ожидание. | |
#define | PT_WAIT_UNTIL(pt, condition) |
Блокирует выполнения и ждет, пока условие не станет true. | |
#define | PT_WAIT_WHILE(pt, cond) |
Блокировка и ожидание, пока условие true. | |
Иераржия protothread-ов | |
#define | PT_WAIT_THREAD(pt, thread) |
Блокирует и ждет, пока не завершится дочерний protothread. | |
#define | PT_SPAWN(pt, child, thread) |
Порождает дочерний protothread и ждет выхода из него. | |
Выход и рестарт | |
#define | PT_RESTART(pt) |
Делает рестарт для protothread. | |
#define | PT_EXIT(pt) |
Выход из protothread. | |
Вызов protothread | |
#define | PT_SCHEDULE(f) |
Шедулинг для protothread. | |
Уступка контекста (Yielding) из protothread | |
#define | PT_YIELD(pt) |
Уступка контекста управления (Yield) из текущего protothread. | |
#define | PT_YIELD_UNTIL(pt, cond) |
Делает уступку процессорного времени из protothread, пока не не будет выполнено условие. |
Протопотоки - это тип облегченных потоков без использования стека, разработанный для систем с малым количеством памяти, таких как встраиваемые (embedded) системы на микроконтролллерах или сетевые узлы датчиков.
Протопотоки предоставляют линейное выполнение кода для событийно-управляемых систем, реализованных на языке C. Протопотоки могут использоваться как совместно с RTOS, так и без нее.
Протопотоки предоставляют блокируемый на ожидании контекст поверх системы, управляемой событиями, без затрат на стек для отдельного потока. Назначение потопотоков - реализовать последовательное выполнение кода без использования сложных машин состояния или многопоточности. Протопотоки предоставляют блокрование выполнения кода по заданному условию внутри тела функций C.
Достоинство протопотоков в том, что с ними достигается чистый событийный механизм, в котором линейное выполнение кода функции может быть заблокировано по нужному условию. В чисто событийных системах блокирование должно быть реализовано вручную, путем разделения функции на 2 части - одна часть для кода до блокирующего вызова, и вторая часть кода после блокирующего вызова. Это делает сложным использование структур управления, таких как оператор условия if() и циклы while().
Достоинство протопотоков по сравнению с обычными потоками в том, что протопоток не требует для себя отдельный стек. В системах, где память является дефицитным ресурсом, выделение нескольких стеков может привести к чрезмерным затратам памяти. В отличие от обычного потока, протопоток требует от 2 до 12 байт для хранения состояния, в зависимости от используемой архитектуры.
Главные особенности:
Примеры приложений, где можно использовать:
API протопотоков состоит из 4 базовых операций. Это инициализация PT_INIT(), выполнение PT_BEGIN(), блокирование на условии PT_WAIT_UNTIL() и выход PT_END(). Кроме того для удобства есть еще 2 функции блокировка по обратному условию PT_WAIT_WHILE() и блокировка на протопотоке PT_WAIT_THREAD().
Protothread-библиотека опубликована под лицензией в стиле BSD, которая позволяет как некоммерческое, так и коммерческое использование. Единственное требование - указать о том, кто автор.
Protothread-библиотека была написана Adam Dunkels <adam@sics.se> с поддержкой Oliver Schmidt <ol.sc@web.de>.
Протопотоки яляются экстремально облегченными, безстековыми потоками, которые предоставляют блокируемый контекст поверх системы, управляемой событиями, без издержек на стек для каждого потока. Назначение протопотоков - реализация последовательного потока выполнения без сложных машин состояния или полного мультитрединга. Протопотоки предоставляют блокрование выполнения кода по заданному условию внутри тела функций C.
В системах с ограниченной памятью (наподобие систем на микроконтроллерах) традиционный мультитрединг приводит к слишком большим расходам памяти. В традиционном мультитрединге для каждого потока требуется отдельный стек, который может занимать большой объем памяти.
Главное достоинство протопотоков по сравнению с обычными потоками в том, что протопоток очень облегчен, и не требует для себя отдельный стек. Вместо этого все протопотоки используют один и тот же стек системы, и переключение контекста происходит методом перемотки стека. Это является достоинством в системах, где память - дефицитный ресурс, потому что выделение нескольких стеков для потоков может привести к чрезмерным затратам памяти. Протопоток требует только 2 байта на один протопоток. Кроме того, протопотоки реализованы на чистом C, и не требуют специфического кода ассемблера, привязанного к архитектуре.
Протопоток работает в пределах единственной функции C и не может охватывать другие функции. Протопоток может вызывать обычные функции C, но внутри вызванной функии блокировка невозможна. Вместо блокировки внутри вызываемой функции делается порождение отдельного протопотока для каждой потенциально блокируемой функции. Достоинство этого подхода в явном блокировании: программист точно знает, какие функции блокируют выполнение, а какие нет.
Протопотоки похожи на асимметричные сопрограммы (co-routines). Главное отличие от сопрограмм в том, что сопрограммы используют стек для каждой сопрограммы, а протопотоки не используют для себя отдельный стек. Наиболее похожий механизм, как у протопотоков, есть у генераторов Python. У них тоже безстековая конструкция, только другое предназначение. Протопотоки предоставляют блокировки контекста внутри функции C, а генераторы Python предоставляют несколько точек выхода из функции генератора.
Протопоток управляется с помощью повторяющихся вызовов функции, в которой протопоток работает. Каждый раз, когда функция вызывается, протопоток будет работать, пока не сделает блокировку или не завершится. Таким образом, шедулинг выполняется приложением, которое использует протопотоки.
Протопотоки реализованы с использованием локальных продолжений. Локальное продолжение представляет текущее состояние выполнения в отдельном месте программы, но не предоставляет какую-либо историю вызовов или локальные переменные. Локальное продолжение может быть установлено в отдельной функции для захвата состояния функции. После того, как локальное продолжение установлено, оно может быть продолжено в виде восстановления состояния функции в той точке, где локальное продолжение было установлено. Прим. переводчика: звучит конечно как бред, но кое-что станет понятно, если посмотрите код макросов протопотоков, и как они используются - например в сетевом приложении hello-world, которое построено на протопотоке.
Локальное продолжение может быть реализовано несколькими способами:
Первый способ работает путем сохранения и восстановления состояния процессора, за исключением указателей стека, и требует от 16 до 32 байт на протопоток. Точное количество памяти зависит от используемой архитектуры процессора.
Реализация на стандартном C требует только 2 байта на протопоток под сохранение состояния, и задействует оператор C switch() неочевидным способом. Эта реализация вводит, однако, небольшое ограничение для кода, который использует протопотоки - сам код не может использовать операторы switch().
У определенных компиляторов есть расширения C, которые можно использовать для реализации протопотоков. GCC поддерживает указатели-метки, которые могут использоваться для этой цели. С такой реализацией протопотоки потребуют 4 байта RAM на один протопоток.
#define PT_BEGIN | ( | pt | ) |
Декларирует начало protothread внутри функции C, реализующей protothread.
Этот макрос используется для декларирования стартовой точки для protothread. Она должна быть размещена в начале функции, в которой запускается protothread. Все операторы C до вызова PT_BEGIN() будут выполнены каждый раз, когда назначается шедулинг для protothread.
pt | Указатель на protothread control structure. |
#define PT_END | ( | pt | ) |
Декларируется конец для protothread.
Этот макрос используется для декларирования места, где заканчивается protothread. Он должен всегда использоваться совместно с соответствующим парным вызовом макроса PT_BEGIN().
pt | Указатель на protothread control structure. |
#define PT_EXIT | ( | pt | ) |
#define PT_INIT | ( | pt | ) |
Инициализация protothread.
Инициализирует protothread. Инициализация должна быть выполнена до начала выполнения protothread.
pt | Указатель на protothread control structure (структура управления). |
#define PT_RESTART | ( | pt | ) |
Делает рестарт для protothread.
Этот макрос заблокирует и перезапустит работающий protothread с того места, где стоит вызов PT_BEGIN().
pt | Указатель на protothread control structure. |
#define PT_SCHEDULE | ( | f | ) |
#define PT_SPAWN | ( | pt, | |
child, | |||
thread | |||
) |
Порождает дочерний protothread и ждет выхода из него.
Этот макрос порождает дочерний protothread и ждет, пока он не выполнит выход. Макрос может быть использован только в пределах protothread. macro can only be used within a protothread.
pt | Указатель на protothread control structure. |
child | Указатель на protothread control structure дочернего protothread. |
thread | Дочерний protothread с аргументами. |
#define PT_THREAD | ( | name_args | ) |
#define PT_WAIT_THREAD | ( | pt, | |
thread | |||
) |
Блокирует и ждет, пока не завершится дочерний protothread.
Этот макрос запускает шедулинг дочернего protothread. Текущий protothread будет заблокирован, пока дочерний protothread не завершится.
pt | Указатель на protothread control structure. |
thread | Дочерний protothread с аргументами. |
#define PT_WAIT_UNTIL | ( | pt, | |
condition | |||
) |
#define PT_WAIT_WHILE | ( | pt, | |
cond | |||
) |
Блокировка и ожидание, пока условие true.
Эта функция блокирует выполнение и ждет, пока условие в состоянии true. См. также PT_WAIT_UNTIL().
pt | Указатель на protothread control structure. |
cond | Условие. |
#define PT_YIELD | ( | pt | ) |
#define PT_YIELD_UNTIL | ( | pt, | |
cond | |||
) |
Делает уступку процессорного времени из protothread, пока не не будет выполнено условие.
pt | Указатель на protothread control structure. |
cond | Условие. |
Эта функция будет приводить к уступке процессорного времени для этого protothread, пока указанное условие вычисляется как true.