Многопоточность

параллельно

Запускает блок кода в отдельном потоке операционной системы:

параллельно
    вывести("Работаю в фоне");
конец

⚠️ Важное ограничение: тело блока параллельно **не может использовать переменные из окружающей области видимости** (защита от обращения к уже освобождённой памяти) — единственное исключение, описанное ниже.

дождаться_все_потоки()

Ждёт завершения всех потоков, запущенных через параллельно с начала программы (или с прошлого вызова этой же функции):

параллельно
    вывести("Поток 1");
конец
параллельно
    вывести("Поток 2");
конец

дождаться_все_потоки();   // гарантированно оба потока уже завершились
вывести("Оба потока точно закончили работу");

⚠️ Честное ограничение: ждёт все потоки разом. Чтобы дождаться одного конкретного — см. дождаться_поток(номер) ниже. Максимум 256 потоков, запущенных без вызова дождаться_все_потоки() между ними.

дождаться_поток(номер)

Ждёт один конкретный поток — номер это порядковый индекс среди запущенных через параллельно с начала программы (или с последнего дождаться_все_потоки()): 0 для первого, 1 для второго и так далее. Возвращает целое (0 при успехе).

параллельно
    вывести("Поток 0");
конец
параллельно
    вывести("Поток 1");
конец

дождаться_поток(0);   // ждёт только первый — второй мог ещё работать
вывести("Поток 0 точно закончил");
дождаться_поток(1);
вывести("Поток 1 тоже закончил");

⚠️ Честные, узкие ограничения (не проверяются во время выполнения):

  • вызывать до дождаться_все_потоки() для той же партии потоков —

тот сбрасывает внутренний учёт, после него дождаться_поток(N) для уже дождавшихся потоков ссылался бы не туда;

  • не вызывать дважды с одним и тем же номером — повторное ожидание уже

завершённого (joined) потока — неопределённое поведение POSIX.

канал\<T\>

Безопасный способ передать одно значение из фонового потока обратно:

функция главная(): целое
    канал из целого канал_результата = создать_канал();

    параллельно
        целое вычислено = 2 + 2;
        канал_результата.отправить(вычислено);
    конец

    целое значение = канал_результата.получить();   // ждёт, пока не придёт значение
    вывести(целое_в_текст(значение));

    вернуть 0;
конец

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

✅ канал из текста безопасен: отправить(...) всегда делает независимую копию текста перед передачей (раньше это был настоящий use-after-free между потоками — см. "Известные ограничения"). ✅ Полученный через получить() текст освобождается автоматически, как и любой другой свежий текст, а сам объект канала можно освободить явно через .освободить() — подробности там же.