Вы находитесь на странице: 1из 11

Министерство науки и высшего образования Российской Федерации

Федеральное государственное бюджетное образовательное учреждение


высшего образования
«Московский государственный технический университет имени
Н.Э. Баумана
(национальный исследовательский университет)» (МГТУ
им. Н.Э. Баумана)

ФАКУЛЬТЕТ Информатика и системы управления (ИУ)

КАФЕДРА Теоретическая информатика и компьютерные технологии (ИУ9)

ОТЧЁТ ПО УЧЕБНОЙ ПРАКТИКЕ

Студент Конюхов Александр Максимович

Группа ИУ9-51

Тип практики Производственная практика ы

Название предприятия МГТУ имени Н. Э. Баумана

Индивидуальный проект

Студент
подпись, дата фамилия, и.о.

Руководитель практики Коновалов А. В.


подпись, дата фамилия, и.о.

Оценка __________________________________

1
СОДЕРЖАНИЕ
1. Постановка задачи…………………………………………………………...………3
2. Описание технологии………………………………………………………………..4
3. Техническая реализация……………………………………………………………..7
4. Сравнение
скорости…………………………………………………………………....................9
5. Заключение………………………………………………………………………….10
6. Литература…………………………………………………………………………..11

2
1. Постановка задачи

Сравнение технических возможностей сопрограмм, реализуемых в стандарте


языка C++ std20. Сравнение подходов написания и проектирования кода, скорость
исполнения. Обзор реализаций сопрограмм в языке C и C++ std17 и позже.

3
2. Описание технологии

Сопрограммы можно рассматривать как обобщение понятия подпрограмм


(routines, функций) в срезе выполняемых над ними операций. Принципиальное
различие между сопрограммами и подпрограммами заключается в том, что
сопрограмма обеспечивает возможность явно приостанавливать свое выполнение,
отдавая контроль другим программным единицам и возобновлять свою работу в
той же точке при получении контроля обратно, с помощью дополнительных
операций, сохраняя локальные данные (состояние выполнения), между
последовательными вызовами, тем самым обеспечивая более гибкий и
расширенный поток управления.

Рисунок 1 Пример работы сопрограммы

Вызов (call). Передача управления вызываемой процедуре. Выполнение операции


можно разделить на несколько этапов:

1. Выделить доступную вызываемой процедуре область памяти — кадр (activation


record, activation frame), необходимого размера;
4
2. Сохранить значения регистров процессора (локальные данные) для
последующего их восстановления, когда управление вернётся из вызываемой
процедуры;
3. Поместить значения аргументов вызова в доступную для процедуры область
памяти. В этой же памяти размещаются локальные переменные;
4. Поместить адрес возврата — адрес команды, следующей за командой вызова в
доступную для процедуры область памяти.

После чего процессор переходит по адресу первой команды вызываемой процедуры,


передавая поток управления.

Возврат из процедуры (return). Передача управления обратно вызывающей


стороне. Выполнение этой операции также состоит из несколько этапов:

1. Сохранить (если необходимо) возвращаемое значение в области памяти


доступной вызывающей процедуре;
2. Удалить локальные переменные, переданные аргументы;
3. Восстановить значения регистров.

Stackful реализации сопрограмм


Как следует из названия, stackful (стековые) сопрограммы — это сопрограммы, у
которых есть свой стек, как и у системных потоков. Основное отличие таких
сопрограмм от обычных системных потоков — это то, что они переключаются
вручную. По сравнению со скоростью переключения системных потоков,
переключение сопрограмм практически бесплатно (сотни тактов процессора). Однако,
из-за того что для каждой сопрограммы надо выделять отдельный стек и прочие
служебные структуры данных — их создание и существование не дешевле, чем
создание системного потока.

В Windows stackful сопрограммы встроены в систему и называются Fibers


(фиберы, волокна).

Stackless реализации сопрограмм


Stackless (безстековые) сопрограммы никак не зависят от операционной
системы, и реализуются исключительно средствами компилятора: код сопрограммы
переписывается в объект-конечный автомат, локальные переменные выделяются не на
стеке, а становятся членами этого объекта.

C++ 20 coroutins

5
В 20 стандарт C++ добавляют долгожданные сопрограммы, компиляторы g++ и
clang уже год назад имеют свои реализации этой технологии. В данной работе я буду
использовать компилятор clang и библиотеку experimental/coroutine.
Простейшая программа, использующая сопрограммы на языке C++ выглядит
примерно следующе:
#include <iostream>
#include "resumable.hpp"

resumable foo() {
std::cout << "Hello" << std::endl;
co_await std::experimental::suspend_always();
std::cout << "World" << std::endl;
}

int main() {
auto t = foo();
t.resume();
std::cout << "Coroutine" << std::endl;
t.resume();
}

Чтобы функция считалась “co” функцией в стандарте C++20, в ней должно


находиться две вещи, co_await/co_yield/co_return и возвращаемый объект должен
реализовывать следующий интерфейс “resumable”:
struct resumable {
struct promise_type {
using coro_t = std::experimental::coroutine_handle<>;
auto get_return_object() {}
auto initial_suspend() {}
auto final_suspend() {}
auto yield_value() {}
auto return_value() {}
void return_void() {}
void unhandled_exception() {}
}
/* нитерфейс работы с сопрограммой */
private:
coro_handle handle_;
}

6
3. Техническая реализация

Реализация автомата C++ 20


В качестве сравнения технических возможностей я выбрал реализацию
интерфейса конечного детерминированного автомата, что достаточно логично
переносится на функционал сопрограмм.
При тестировании будет использоваться следующий автомат:
A -- 'a' --> B
A -- 'b' --> C
B -- 'a' --> C
B -- 'b' --> A
C -- 'a' --> A
C -- 'b' --> B
Идея реализации была подсмотрена у Владимиров К. И.
Интерфейс реализует класс state_machine, в основе которого лежат
сопрограммы. Пользователь задает функцию перехода translate, которая отображает
структуру автомата и задается пользователем, структуры State и Sym, состояния и
символы автомата соответственно и “co” функции к каждому состоянию автомата.
После создания объекта и добавления состояний, автомат готов к работе.
Полный код находится в github : https://github.com/coudam/coroutines/tree/master/cpp

Реализация автомата на языке C с использованием сопрограмм, реализованных


помощью switch и макросов:
#include <stdio.h>
#include <time.h>

#define start(state) \
switch (state) { \
case 0:;

#define finish \
default:; \
}
7
#define yield(state, value) \
do { \
state = __LINE__; \
return (value); \
case __LINE__:; \
} while (0)

int run(char input) {


static int state = 0;
start(state) {
A:
printf("A\n");
yield(state, 1);
if (input == 'a')
goto B;
if (input == 'b')
goto C;
B:
printf("B\n");
yield(state, 2);
if (input == 'a')
goto C;
if (input == 'b')
goto A;
C:
printf("C\n");
yield(state, 3);
if (input == 'a')
goto A;
if (input == 'b')
goto B;
}
finish;

return 0;
}

int main() {
int a, s = 0, t;
clock_t start, fin;
start = clock();
while ((a = getchar()) != EOF && (s = run(a)) != 0) {
t = s;
}
8
fin = clock();

printf("Elapsed: %lg seconds\n", (double)(fin — start) / CLOCKS_PER_SEC);


printf("final: %d\n", t);
return 0;
}

4. Сравнение скорости

 state_machine_coro – автомат на сопрограммах


 state_machine_no_coro – автомат на языке C
Компиляция под Linux:
 clang -O2 fsm_measure.c -o state_machine_no_coro
 clang++ -O2 -stdlib=libc++ -std=c++20 state_machine_measure.cpp -o
state_machine_coro

Рисунок 2 Итоги замера скорости

9
5. Заключение

К сожалению заявление Гора Нишанова о том, что сопрограммы являются


абстракцией с отрицательной стоимостью разбиваются о реальное тестирование.
Оверхед на использование сопрограмм все же есть. Но при использовании сопрограмм
в более сложных и комплексных программах, где полезной работы в “co” функциях
будет больше, оверхед будет незаметнее, но интерфейс реализованный с помощью
сопрограмм будет намного понятнее и проще.
И так же, используемый мной компилятор при тестировании – это тестовая
реализацию 20 стандарта, возможно после официального выхода 20 стандарта,
компиляторы получат более оптимальную реализацию, что приведет к уменьшению
оверхеда на использование сопрограмм.
Делая выводы можно сказать что сопрограммы – это отличный инструмент в
умелых руках, который позволяет делать простые интерфейсы, по сравнению с
другими подходами, а также имеет большой потенциал в работе с многопоточностью в
C++.

10
6. Литература

 Реализация конечного автомата на С:


https://stackoverflow.com/questions/20701834/implementing-a-finite-state-machine-
with-a-single-coroutine
 Презентация Гора Нишанова на CppCon: https://www.youtube.com/watch?
v=8C8NnE1Dg4A&ab_channel=CppCon
 C++20 драфт сопрограмм: http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2018/n4775.pdf
 ISO/IEC, "Information technology -- Programming languages – C++", ISO/IEC
14882:2017
 Bjarne Stroustrup, The C++ Programming Language (4th Edition)

11