Співпрограма або співпроцедура (англ. Coroutine) — компонент програми, що узагальнює поняття підпрограми, додатковою підтримкою безлічі точок входу (а не однієї, як підпрограма) і зупинку та продовження виконання із збереженням певного положення. Співпрограми є гнучкішими і узагальненішими, ніж підпрограми, але рідше використовуються на практиці. Застосування співпрограм, будучи методикою ще асемблера, практикувалося лише деякими високорівневими мовами, наприклад Simula і Modula-2. Співпрограми добре придатні для реалізації багатьох схожих компонентів програм (ітераторів, нескінченних списків, каналів, волокон).

Співпрограма має початкову точку входу і розташовані всередині послідовності повернень і наступних точок входу. Підпрограмма може повертати керування лише одного разу, співпрограма може повертати керування багаторазово. Час роботи підпрограми відзначається принципом LIFO (остання викликана підпрограма завершується першою), час роботи співпрограми визначається її використанням і необхідністю.

Наведемо простий приклад використання співпрограми. Нехай необхідно реалізувати зв'язок між споживачем і виробником, де одна частина програми створює елементи й поміщає їх у чергу, а інша видаляє їх та використовує. Наступний код реалізує це:

var q := new queue
 
coroutine produce
    loop
        while q is not full
            create some new items
            add the items to q
        yield to consume
 
coroutine consume
    loop
        while q is not empty
            remove some items from q
            use the items
        yield to produce

Реалізації ред.

C++ ред.

Підтримка співпрограм існувала в ранніх версіях C++, але через низку різних причин у стандарт C++98 співпрограми не увійшли[1].

В 2012 році комітет отримав формальну пропозицію з включення підтримки співпрограм. Головним чином, вони були потрібні для створення серверних застосунків з підтримкою тисяч або навіть мільйонів одночасних клієнтів. В 2013 році була запропонована альтернативна реалізація. Відтоді тривали дискусії, дослідження, спроби узгодити остаточну версію[1].

Нарешті, підтримка безстекових сівпрограм увійшла в стандарт мови C++20[1]. Зокрема, були додані нові ключові слова co_return, co_await та co_yield, але підтримка співпрограм у стандартній бібліотеці була мінімальна[2].

До того можливість роботи зі співпрограмами була реалізована на рівні бібліотек, зокрема Boost.Coroutine, Boost.Coroutine2 та іншими[2], стандарт радше визначив каркас для роботи зі співпрограмами[3]. Тому, для зручності розробників, були створені бібліотеки класів для поширених видів співпрограм: cppcoro, libcoro, QCoro, та інші[2].

Стандартом передбачено, що співпрограма може віддати управління в одному потоці виконання, а бути відновлена — в іншому[4].

В стандарті C++23 був доданий тип generator, який полегшує створення генераторів послідовностей на основі співпрограм сумісних з доданими в стандарті C++20 діапазонами[5].

Таким чином, генератор послідовності Фібоначчі мовою стандарту C++23 може мати такий вигляд:

#include <generator>
#include <ranges>
#include <iostream>
 
std::generator<int> fib() {
    co_yield 0;
    auto a = 0;
    auto b = 1;
    for (auto n : std::views::iota(0)) {  
        auto next = a + b;
        a = b;
        b = next;
        co_yield next;
    }
}

int main() {
    for (auto f : fib() | std::views::take(10)) {
        std::cout << f << " ";
    }
}

Див. також ред.

Примітки ред.

  1. а б в Stroustrup, Bjarne (12 червня 2020). Thriving in a crowded and changing world: C++ 2006–2020. Proceedings of the ACM on Programming Languages. Association for Computing Machinery (ACM). 4 (HOPL): 1—168. doi:10.1145/3386320. ISSN 2475-1421. S2CID 219603741.
  2. а б в Valentyn Korniienko (25 квітня 2023). С++20 Сoroutines та огляд бібліотек, які реалізують підтримку со-програм. DOU.
  3. Rainer Grimm (23 жовтня 2019). C++20: The Big Four.
  4. Coroutines (C++20). CPP Reference. 27 жовтня 2023. Процитовано 4 листопада 2023.
  5. Rainer Grimm (18 вересня 2023). C++23: Ranges Improvements and std::generator.