Многопоточность
параллельно
Запускает блок кода в отдельном потоке операционной системы:
параллельно
вывести("Работаю в фоне");
конец
⚠️ Важное ограничение: тело блока параллельно **не может
использовать переменные из окружающей области видимости** (защита от
обращения к уже освобождённой памяти) — единственное исключение,
описанное ниже.
дождаться_все_потоки()
Ждёт завершения всех потоков, запущенных через параллельно с
начала программы (или с прошлого вызова этой же функции):
параллельно
вывести("Поток 1");
конец
параллельно
вывести("Поток 2");
конец
дождаться_все_потоки(); // гарантированно оба потока уже завершились
вывести("Оба потока точно закончили работу");
⚠️ Честное ограничение: ждёт все потоки разом. Чтобы дождаться
одного конкретного — см. дождаться_поток(номер) ниже. Максимум 256
потоков, запущенных без вызова дождаться_все_потоки() между ними.
дождаться_поток(номер)
Ждёт один конкретный поток — номер это порядковый индекс среди
запущенных через параллельно с начала программы (или с последнего
дождаться_все_потоки()): 0 для первого, 1 для второго и так
далее. Возвращает целое (0 при успехе).
параллельно
вывести("Поток 0");
конец
параллельно
вывести("Поток 1");
конец
дождаться_поток(0); // ждёт только первый — второй мог ещё работать
вывести("Поток 0 точно закончил");
дождаться_поток(1);
вывести("Поток 1 тоже закончил");
⚠️ Честные, узкие ограничения (не проверяются во время выполнения):
- вызывать до
дождаться_все_потоки()для той же партии потоков —
тот сбрасывает внутренний учёт, после него дождаться_поток(N) для
уже дождавшихся потоков ссылался бы не туда;
- не вызывать дважды с одним и тем же номером — повторное ожидание уже
завершённого (joined) потока — неопределённое поведение POSIX.
канал\<T\>
Безопасный способ передать одно значение из фонового потока обратно:
функция главная(): целое
канал из целого канал_результата = создать_канал();
параллельно
целое вычислено = 2 + 2;
канал_результата.отправить(вычислено);
конец
целое значение = канал_результата.получить(); // ждёт, пока не придёт значение
вывести(целое_в_текст(значение));
вернуть 0;
конец
Поддерживаются только целочисленные и указательные типы значения (не дробные, не встроенные напрямую структуры).
✅ канал из текста безопасен: отправить(...) всегда делает независимую
копию текста перед передачей (раньше это был настоящий use-after-free
между потоками — см. "Известные ограничения"). ✅ Полученный через
получить() текст освобождается автоматически, как и любой другой
свежий текст, а сам объект канала можно освободить явно через
.освободить() — подробности там же.