UN NewsWHO releases first global guidelines on child obesity as cases surgeESPN📈 Ovechkin's retirement announcement sparks major ticket price hikePunchBarcelona hails Messi’s remarkable career with ArgentinaThe Jerusalem PostHamam al-Hammami hired by flydubai as part of airline's mass hiring push - reportBollywood HungamaGuneet Monga Kapoor-led Women in Film India and Google Flow join hands to enable AI-powered filmmaking for new creative possibilitiesInquirerDTI maps halal calamansi supply chain in Oriental MindoroCapital FMPharmacists told to be on alert as Kenya confirms imported Ebola caseZDF heuteAktuelle Pressemitteilungen des ZDFCollider‘Mistborn’ Movie Script Is Officially Finished as Brandon Sanderson Reveals Next Step [Exclusive]SDP EspectáculosReseña de Carrie: una buena actualización de Prime Video, pero ¿dónde quedó el horror?Daily MaverickDANCE REVIEW: Elysium — 4 dances of bliss and seduction, transcendence and joy from Cape Ballet AfricaGIGAZINEChatGPTが生成したマンガに「実在するマンガ家の署名」が含まれているとの指摘
The Daily Newsstand · Free, Always
Wednesday, October 7, 2026

Потоки, события и ожидание результата: многозадачность в PL/I

Translate

Когда говорят о PL/I, воображение часто рисует большие машины и программы из другой эпохи. Но у языка есть и вполне современная сторона: процедуры, массивы, многопоточное выполнение. Если вы писали на Go или Python, базовый сценарий будет понятен: запустить работу в фоне, пока она идёт заняться чем‑то ещё, а затем дождаться результата.

Разберём этот сценарий на примерах, которые опираются на реализованную многозадачность в pli‑llvm — новом открытом кроссплатформенном компиляторе языка PL/I, который был создан на основе спецификации языка TR25 с добавлением некоторых более поздних полезных фишек из IBM Enterprise PL/I.

Запустить задачу и дождаться её завершения

В Go для этого обычно используют горутину и sync.WaitGroup, в Python — поток и join(). В PL/I аналогичную задачу выполняют call … event(…) и wait(…):

demo: proc options(main);
  dcl done event; 
  dcl counter fixed bin(31) init(0);

  call worker event(done);

  put skip list(‘main continues’); 
  wait(done);

  put skip list(‘counter =’, counter);

worker: proc; 
  counter = counter + 1; 
end; 

end demo;

call запускает процедуру worker в фоновом потоке, а wait(done) приостанавливает главный поток до завершения задачи. После этого программа читает значение counter. Для сравнения — аналогичный код на Go:

var wg sync.WaitGroup
wg.Add(1)

go func() {
    defer wg.Done()
    counter++
}()

wg.Wait()

В Python с модулем threading:

thread = threading.Thread(target=worker)
thread.start()
thread.join()

Синтаксис различный, но порядок действий один: запустить независимую работу, заняться своим делом и синхронизироваться перед использованием результата.

Две независимые задачи

Допустим, что нужно посчитать две части набора данных. Запустим для каждой отдельную задачу, а пока они работают — выполним отдельную небольшую задачу в главном потоке:

concurrency: proc options(main);
   dcl (left_done, right_done) event;

   dcl left_sum fixed bin(63) init(0),
       right_sum fixed bin(63) init(0);

   dcl foreground fixed bin(31) init(0);
   dcl i fixed bin(31);

   /* запуск подзадач */
   call sum_left event(left_done);
   call sum_right event(right_done);

   /* параллельное выполнение задачи в основном потоке */
   do i = 1 to 100;
     foreground = foreground + i;
   end;

   wait(left_done, right_done);

   put skip list('left =', left_sum);
   put skip list('right =', right_sum);
   put skip list('foreground =', foreground);

 sum_left: proc;
   dcl i fixed bin(31);
   do i = 1 to 100000;
     left_sum = left_sum + i;
   end;
 end;

 sum_right: proc;
   dcl i fixed bin(31);
   do i = 100001 to 200000;
     right_sum = right_sum + i;
   end;
 end;

 end;

Для каждой задачи есть своё событие: left_done и right_done. Вызов wait с обоими событиями ждёт завершения обеих процедур. Каждая из них записывает в собственную переменную результата — общего изменяемого счётчика здесь нет.

Когда нужен результат — проверить или подождать

Обычно проще вызвать wait, но иногда нужно периодически проверять, закончилась ли задача. Встроенная функция event возвращает '1’b (соответствует true), когда событие завершено, delay(n) задает паузу на n миллисекунд:

do while (^event(done));
   put skip list('still working...');
   delay(50);
 end;

Так цикл не проверяет состояние непрерывно и не тратит процессор впустую. Для групп событий предусмотрена и форма wait(events)(k): она ждёт завершения любых k событий из списка или массива.

Несколько деталей, о которых стоит помнить

В данной реализации PL/I асинхронный call выполняется в фоновом потоке. Событие можно объявить отдельно, элементом массива или полем структуры. Поддерживаются события с постоянными границами массива; динамические размеры для этой формы пока что не реализованы.

Событие должно оставаться доступным, пока задача выполняется, поэтому нужно дожидаться её завершения до выхода из блока, где объявлено событие. А если несколько задач записывают в одну переменную, потребуется отдельно продумывать синхронизацию: механизм событий сам по себе не реализовывает безопасный параллельный доступ к данным.

Запуск и компиляция

Компилятор является самодостаточным исполняемым файлом, поэтому достаточно скачать релиз под свою платформу с GitHub, распаковать и добавить в переменную PATH, затем скомпилировать код из примера и запустить:

plic concurrency.pli -o concurrency
./concurrency

Результат выполнения:

left = 5000050000
right = 15000050000
foreground = 5050

Также можно собрать компилятор из исходного кода самостоятельно под свою платформу следую инструкциям в README.

Почему PL/I

Язык PL/I интересен тем, что сочетает скорость C с высокоуровневыми фишками современных языков типа Go и Python — такими, как встроенная многозадачность, сигналы и управление памятью на уровне семантики языка. При этом он не имеет зарезервированных слов, что дает свободу в выборе имен переменных и функций, а дизайн языка делает код легкочитаемым и позволяет писать быстрые программы для высокопроизводительных вычислений.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.