Оболочка C - C shell

Оболочка C
Tcsh ejecutándose en escritorio Mac OSX.png
tcsh и sh бок о бок на рабочем столе Mac OS X
Автор (ы) оригинала Билл Джой
изначальный выпуск 1978 ; 43 года назад ( 1978 )
Стабильный выпуск
6.20.00 / 24 ноября 2016 г . ; 4 года назад ( 2016-11-24 )
Репозиторий Отредактируйте это в Викиданных
Написано в C
Операционная система BSD , UNIX , Linux , macOS
Тип Оболочка Unix
Лицензия Лицензия BSD
Оболочка C, работающая в службах Windows для UNIX

Оболочка C ( CSH или улучшенная версия, Tcsh ) является Unix оболочки , созданный Билл Джой , когда он был аспирантом в Университете Калифорнии, Беркли , в конце 1970 - х годов. Он получил широкое распространение, начиная с выпуска 2BSD Berkeley Software Distribution (BSD), который Joy впервые распространил в 1978 году. Другими ранними участниками идеи или кода были Майкл Убелл, Эрик Аллман , Майк О'Брайен и Джим Калп.

Оболочка C - это командный процессор, который обычно запускается в текстовом окне, позволяя пользователю вводить и выполнять команды. Оболочка C также может читать команды из файла, называемого сценарием . Как и все оболочки Unix, он поддерживает подстановочные знаки имен файлов , конвейерную передачу , здесь документы , подстановку команд , переменные и управляющие структуры для проверки условий и итераций . Что отличало оболочку C от других, особенно в 1980-х годах, так это ее интерактивные функции и общий стиль. Его новые функции сделали его проще и быстрее в использовании. Общий стиль языка больше походил на C и считался более читабельным.

Во многих системах, таких как macOS и Red Hat Linux , csh на самом деле является tcsh , улучшенной версией csh. Часто один из двух файлов представляет собой жесткую или символическую ссылку на другой, так что любое имя относится к одной и той же улучшенной версии оболочки C.

В Debian и некоторых производных (включая Ubuntu ) есть два разных пакета: csh и tcsh. Первый основан на оригинальной BSD-версии csh, а второй - улучшенный tcsh.

В tcsh добавлены концепции завершения имени файла и команд и редактирования командной строки, заимствованные из системы Tenex , которая является источником символа «t». Поскольку он только добавлял функциональность и не менял того, что было, tcsh оставался обратно совместимым с исходной оболочкой C. Хотя он начинался как побочная ветка от исходного дерева исходных текстов, созданного Джой, теперь tcsh является основной ветвью для продолжающейся разработки. tcsh очень стабилен, но новые выпуски продолжают появляться примерно раз в год, в основном состоящие из мелких исправлений ошибок.

Цели и особенности дизайна

Основные цели разработки оболочки C заключались в том, чтобы она больше походила на язык программирования C и была лучше для интерактивного использования.

Больше похоже на C

Система Unix была написана почти исключительно на C, поэтому первой целью оболочки C был командный язык, который стилистически более соответствовал остальной части системы. Ключевые слова, использование круглых скобок, грамматика встроенных выражений оболочки C и поддержка массивов - все это находилось под сильным влиянием C.

По сегодняшним стандартам оболочка C может показаться не более похожей на C, чем многие другие популярные языки сценариев. Но на протяжении 80-х и 90-х годов разница казалась поразительной, особенно по сравнению с оболочкой Bourne (также известной как sh ), доминирующей в то время оболочкой, написанной Стивеном Борном из Bell Labs . Этот пример иллюстрирует более обычные С оболочкой операторов экспрессии и синтаксис .

Оболочка Борна

#!/bin/sh
if [ $days -gt 365 ]
then
   echo This is over a year.
fi

Оболочка C

#!/bin/csh
if ( $days > 365 ) then
   echo This is over a year.
endif

В Bourne sh отсутствовала грамматика выражений . Условия, заключенные в квадратные скобки, должны были быть оценены более медленными средствами выполнения внешней тестовой программы. ifКоманда sh приняла свои аргументные слова как новую команду, запускаемую как дочерний процесс . Если дочерний процесс завершился с нулевым кодом возврата , sh будет искать предложение then (отдельный оператор, но часто пишется, соединенный в той же строке точкой с запятой) и запускает этот вложенный блок. В противном случае он запустил бы else. Жесткая компоновка тестовой программы как " test", так и " [" дала преимущество в виде квадратных скобок и создавала впечатление, что функциональные возможности теста являются частью языка sh. Использование в sh ключевого слова reversed для обозначения конца блока управления было стилем, заимствованным из АЛГОЛА 68 .

Напротив, csh может вычислять выражение напрямую, что делает его быстрее. Он также заявлял о лучшей читабельности: в его выражениях использовалась грамматика и набор операторов, в основном скопированных с C, ни одно из его ключевых слов не было перевернуто, и общий стиль также был больше похож на C.

Вот второй пример сравнения скриптов, которые вычисляют первые 10 степеней двойки.

Оболочка Борна

#!/bin/sh
i=2
j=1
while [ $j -le 10 ]
do
   echo '2 **' $j = $i
   i=`expr $i '*' 2`
   j=`expr $j + 1`
done

Оболочка C

#!/bin/csh
set i = 2
set j = 1
while ( $j <= 10 )
   echo '2 **' $j = $i
   @ i *= 2
   @ j++
end

Опять же из-за отсутствия грамматики выражений сценарий sh использует подстановку команд и команду expr . (Современная оболочка POSIX действительно имеет такую ​​грамматику: оператор может быть написан i=$((i * 2))или : $((i *= 2)).)

Наконец, вот третий пример, показывающий разные стили для оператора switch .

Оболочка Борна

#!/bin/sh
for i in d*
do
   case $i in
      d?) echo $i is short ;;
      *) echo $i is long ;;
   esac
done

Оболочка C

#!/bin/csh
foreach i ( d* )
   switch ( $i )
      case d?:
         echo $i is short
         breaksw
      default:
         echo $i is long
   endsw
end

В сценарии sh символ " ;;" отмечает конец каждого случая, потому что в противном случае sh запрещает пустые операторы.

Улучшения для интерактивного использования

Вторая цель заключалась в том, чтобы оболочка C была лучше для интерактивного использования. Он представил множество новых функций , которые сделали это проще, быстрее и более дружественной для использования команд печатают на терминале. Пользователи могли выполнять задачи с меньшим количеством нажатий клавиш, и он работал быстрее. Наиболее важными из этих новых функций были механизмы истории и редактирования, псевдонимы, стеки каталогов, тильда, cdpath, управление заданиями и хеширование пути. Эти новые функции оказались очень популярными, и многие из них с тех пор были скопированы другими оболочками Unix.

История

История позволяет пользователям вспомнить предыдущие команды и повторно запустить их, набрав всего несколько быстрых нажатий клавиш. Например, ввод двух восклицательных знаков (« !!») в качестве команды приводит к запуску непосредственно предшествующей команды. Другие комбинации коротких нажатий клавиш, например, « !$» (что означает «последний аргумент предыдущей команды»), позволяют вставлять фрагменты предыдущих команд вместе и редактировать их для формирования новой команды.

Операторы редактирования

Редактировать можно не только текст предыдущей команды, но и замену переменных. Операторы варьируются от простого поиска / замены строки до анализа имени пути для извлечения определенного сегмента.

Псевдонимы

Псевдонимы позволяют пользователю ввести имя псевдонима и заставить оболочку C развернуть его внутри любого набора слов, определенных пользователем. Во многих простых ситуациях псевдонимы работают быстрее и удобнее сценариев.

Стек каталогов

Каталог стека позволяет пользователю нажать или поп на текущий рабочий каталог , что делает его легче прыгать взад и вперед между различными местами в файловой системе.

Обозначение тильды

Обозначение тильды предлагает сокращенный способ указания путей относительно домашнего каталога с помощью ~символа " ".

Завершение имени файла

Клавишу escape можно использовать интерактивно, чтобы показать возможные дополнения имени файла в конце текущей командной строки.

Cdpath

Cdpath расширяет понятие пути поиска до команды cd(сменить каталог): если указанный каталог не находится в текущем каталоге , csh попытается найти его в каталогах cdpath.

Контроль работы

Вплоть до 1980-х годов у большинства пользователей были только простые терминалы в символьном режиме, которые исключали использование нескольких окон, поэтому они могли работать только над одной задачей за раз. Элемент управления заданием оболочки C позволяет пользователю приостановить текущее действие и создать новый экземпляр оболочки C, называемый заданием, путем ввода ^Z. Затем пользователь мог переключаться между заданиями с помощью fgкоманды. Говорили, что активная работа находится на переднем плане. Другие задания были либо приостановлены (остановлены), либо выполнялись в фоновом режиме .

Хеширование пути

Хеширование пути ускоряет поиск исполняемых файлов оболочкой C. Вместо того, чтобы выполнять вызов файловой системы в каждом каталоге пути, по одному, пока он либо не найдет файл, либо не исчерпает все возможности, оболочка C обращается к внутренней хэш-таблице, построенной путем сканирования каталогов пути. Эта таблица обычно сообщает оболочке C, где найти файл (если он существует) без необходимости поиска, и может быть обновлена ​​с помощью rehashкоманды.

Обзор языка

Оболочка C работает по одной строке за раз. Каждая строка токенизируется в набор слов, разделенных пробелами или другими символами со специальным значением, включая круглые скобки, конвейеры и операторы перенаправления ввода / вывода, точки с запятой и амперсанды.

Основные утверждения

Базовый оператор - это просто запуск команды. Первое слово используется как имя команды, которая должна быть запущена, и может быть либо внутренней командой, например,, echoлибо внешней командой. Остальные слова передаются команде в качестве аргументов.

На базовом уровне утверждения вот некоторые особенности грамматики:

Подстановочные знаки

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

  • * соответствует любому количеству символов.
  • ? соответствует любому одиночному символу.
  • [... ]соответствует любому из символов в квадратных скобках. Допускаются диапазоны с использованием дефиса.
  • [^... ]соответствует любому символу не в наборе.

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

  • abc{def,ghi}является чередованием (также известным как расширение скобок ) и расширяется до abcdef abcghi .
  • ~ означает домашний каталог текущего пользователя.
  • ~userсредства пользователя» домашний каталог.

*/*.cПоддерживаются несколько подстановочных знаков уровня каталога, например " ".

Начиная с версии 6.17.01, с опцией также поддерживается рекурсивный подстановочный знак à la zsh (например, " **/*.c" или " ***/*.html") globstar.

Предоставление оболочке ответственности за интерпретацию подстановочных знаков было важным решением для Unix. Это означало, что подстановочные знаки будут работать с каждой командой и всегда одинаково. Однако это решение основывалось на способности Unix эффективно передавать длинные списки аргументов через системный вызов exec, который csh использует для выполнения команд. Напротив, в Windows интерпретация подстановочных знаков обычно выполняется каждым приложением. Это наследие MS-DOS, которое позволяло передавать приложению только 128-байтовую командную строку, что делало использование подстановочных знаков в командной строке DOS непрактичным. Хотя современная Windows может передавать командные строки длиной до 32 КБ символов Unicode , бремя интерпретации подстановочных знаков остается за приложением.

Перенаправление ввода / вывода

По умолчанию, когда csh запускает команду, команда наследует дескрипторы файлов stdio csh для stdin , stdout и stderr , которые обычно все указывают на окно консоли, в котором запущена оболочка C. Операторы перенаправления ввода-вывода позволяют команде использовать файл вместо ввода или вывода.

  • > file означает, что stdout будет записан в файл , перезаписывая его, если он существует, и создавая его, если нет. Ошибки по-прежнему приходят в окно оболочки.
  • >& file означает, что и stdout, и stderr будут записаны в файл , перезаписывая его, если он существует, и создавая его, если это не так.
  • >> file означает, что стандартный вывод будет добавлен в конец файла .
  • >>& file означает, что и stdout, и stderr будут добавлены в конец файла .
  • < файл означает, что стандартный ввод будет читаться из файла .
  • << строка - это здесь документ . Stdin будет читать следующие строки до той, которая соответствует строке .

Присоединение

Команды можно объединять в одной строке.

  • ; означает выполнение первой команды, а затем следующей.
  • &&означает выполнить первую команду и, если она завершится успешно с кодом возврата 0 , запустить следующую.
  • || означает выполнение первой команды и, если она не удалась с ненулевым кодом возврата, запустить следующую.

Трубопровод

Команды могут быть связаны с помощью канала, который заставляет вывод одной команды подавать на ввод следующей. Обе команды выполняются одновременно .

  • |означает подключение стандартного вывода к стандартному вводу следующей команды. Ошибки по-прежнему приходят в окно оболочки.
  • |& означает подключение как stdout, так и stderr к stdin следующей команды.

Выполнение одновременно означает «параллельно». В многоядерной (многопроцессорной) системе переданные по конвейеру команды могут выполняться буквально одновременно, в противном случае планировщик в операционной системе разделяет их по времени.

По команде, например " a | b", оболочка создает канал , а затем запускает оба aи bсо стандартным вводом для двух перенаправленных команд так, что aзаписывает свой стандартный вывод во вход канала, а bчитает стандартный ввод из вывода канала. Каналы реализуются операционной системой с определенной степенью буферизации, чтобы aможно было писать в течение некоторого времени, прежде чем канал заполнится, но после заполнения канала любая новая запись будет блокироваться внутри ОС до тех пор, пока не будет bпрочитано достаточно, чтобы разблокировать новые записи. Если bпытается прочитать больше данных, чем доступно, он будет блокироваться до aтех пор, пока не будет записано больше данных или пока канал не закроется, например, при aвыходе.

Замена переменных

Если слово содержит знак доллара " $", следующие символы принимаются в качестве имени переменной, а ссылка заменяется значением этой переменной. Различные операторы редактирования, введенные как суффиксы к ссылке, позволяют редактировать имя пути (например, " :e" для извлечения только расширения) и другие операции.

Цитирование и экранирование

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

  • \ означает принять следующий символ как обычный буквальный символ.
  • "строка" - слабая кавычка. Заключенные пробелы и подстановочные знаки принимаются как литералы, но подстановки переменных и команд по-прежнему выполняются.
  • 'строка' - сильная кавычка. Вся заключенная строка воспринимается как литерал.

Подстановка команд

Подстановка команд позволяет использовать вывод одной команды в качестве аргументов для другой.

  • `Команда` означает взять вывод команды , разобрать его на слова и вставить обратно в командную строку.

Фоновое выполнение

Обычно, когда оболочка C запускает команду, она ожидает ее завершения, прежде чем дать пользователю еще одно приглашение, сигнализирующее о том, что можно ввести новую команду.

  • Команда & означает запуск команды в фоновом режиме и немедленный запрос новой команды.

Подоболочки

Подоболочка - это отдельная дочерняя копия оболочки, которая наследует текущее состояние, но затем может вносить изменения, например, в текущий каталог, не затрагивая родительский.

  • ( команды ) означает запускать команды в подоболочке.

Структуры управления

Оболочка C предоставляет управляющие структуры как для проверки условий, так и для итераций . Управляющими структурами проверки условий являются операторы if и switch. Структуры управления итерацией - это операторы while, foreach и repeat.

если заявление

Есть две формы оператора if . Краткая форма печатается в одной строке, но может указывать только одну команду, если выражение истинно.

if ( expression ) command

В длинной форме используются ключевые слова then, else и endif, позволяющие вставлять блоки команд внутри условия.

if ( expression1 ) then
    commands
else if ( expression2 ) then
    commands
    ...
else
    commands
endif

Если ключевые слова else и if появляются в одной строке, csh объединяет их в цепочку, а не вкладывает их; блок заканчивается одним endif.

оператор переключения

Оператор switch сравнивает строку со списком шаблонов, который может содержать подстановочные знаки. Если ничего не совпадает, выполняется действие по умолчанию, если оно есть.

switch ( string )
    case pattern1:
        commands
        breaksw
    case pattern2:
        commands
        breaksw
        ...
    default:
        commands
        breaksw
endsw

в то время как заявление

Оператор while оценивает выражение. Если это правда, оболочка запускает вложенные команды, а затем повторяет их, пока выражение остается истинным.

while ( expression )
    commands
end

оператор foreach

Оператор foreach принимает список значений, обычно список имен файлов, созданный с помощью подстановочных знаков, а затем для каждого устанавливает переменную цикла на это значение и запускает вложенные команды.

foreach loop-variable ( list-of-values )
    commands
end

повторить заявление

Оператор repeat повторяет одну команду целое число раз.

repeat integer command

Переменные

Оболочка C реализует переменные оболочки и среды . Переменные среды, созданные с помощью setenvоператора, всегда представляют собой простые строки, передаваемые любым дочерним процессам , которые получают эти переменные через envp[]аргумент для main().

Переменные оболочки, созданные с помощью операторов setили @, являются внутренними для оболочки C. Они не передаются дочерним процессам. Переменные оболочки могут быть простыми строками или массивами строк. Некоторые из переменных оболочки предопределены и используются для управления различными внутренними параметрами оболочки C, например, что должно произойти, если подстановочный знак не соответствует чему-либо.

В текущих версиях csh строки могут иметь произвольную длину, вплоть до миллионов символов.

Выражения

Оболочка C реализует грамматику 32-битных целочисленных выражений с операторами, заимствованными из C, но с несколькими дополнительными операторами для сравнения строк и тестов файловой системы, например, проверки существования файла. Операторы должны отделяться от своих операндов пробелами. Переменные обозначаются как $имя .

Приоритет операторов также заимствован из C, но с другими правилами ассоциативности операторов для разрешения неоднозначности того, что идет первым в последовательности операторов с одинаковым приоритетом. В C ассоциативность для большинства операторов слева направо; в оболочке C - справа налево. Например,

// C groups from the left
int i = 10 / 5 * 2;
printf( "%d\n", i ); // prints 4
i = 7 - 4 + 2;
printf( "%d\n", i ); // prints 5
i = 2 >> 1 << 4;
printf( "%d\n", i ); // prints 16
# C shell groups from the right
@ i = 10 / 5 * 2
echo $i # prints 1
@ i = 7 - 4 + 2
echo $i # prints 1
@ i = ( 2 >> 1 << 4 )
echo $i # prints 0

Скобки в примере оболочки C предназначены для того, чтобы операторы битового сдвига не путались с операторами перенаправления ввода-вывода. На любом языке всегда можно использовать круглые скобки, чтобы явно указать желаемый порядок оценки, даже если только для ясности.

Прием

Хотя сам Стивен Борн признал, что csh лучше его оболочки для интерактивного использования, он никогда не был так популярен для написания сценариев. Изначально и до 1980-х годов нельзя было гарантировать наличие csh во всех системах Unix, но sh мог, что делало его лучшим выбором для любых сценариев, которые, возможно, придется запускать на других машинах. К середине 1990-х годов csh был широко доступен, но использование csh для написания сценариев столкнулось с новой критикой со стороны комитета POSIX , который указал, что должна быть только одна предпочтительная оболочка, KornShell , как для интерактивных целей, так и для сценариев. Оболочка C также подверглась критике со стороны других по поводу предполагаемых дефектов синтаксиса оболочки C, отсутствующих функций и плохой реализации.

  • Дефекты синтаксиса: обычно были простыми, но ненужными несоответствиями в определении языка. Например, все команды set, setenvи aliasделают в основном одно и то же, а именно связывают имя со строкой или набором слов. Но у всех троих были небольшие, но ненужные различия. Знак равенства требовался для a, setно не для setenvили alias; Скобки должны были вокруг списка слова для setно не для setenvили alias, и т.д. Точно так же, как if, switchи циклических конструкции используют без необходимости других ключевых слов ( endif, endswи end) , чтобы прекратить вложенные блоки.
  • Недостающие функции: чаще всего упоминаются отсутствие возможности независимо управлять дескрипторами файлов stdio и поддержка функций. В то время как в функциях оболочки Bourne отсутствовали только локальные переменные, псевдонимы Csh - ближайший аналог функций в Csh - были ограничены отдельными строками кода, хотя большинство конструкций управления потоком требовали распознавания новой строки. В результате скрипты Csh не могли быть функционально разбиты, как могли бы быть сами программы C, и более крупные проекты имели тенденцию переходить либо на сценарии оболочки Bourne, либо на код C.
  • Реализация, в которой использовался специальный синтаксический анализатор , вызвала самую серьезную критику. К началу 1970-х годов технология компиляторов была достаточно зрелой, поэтому в большинстве новых языковых реализаций использовался нисходящий или восходящий синтаксический анализатор, способный распознавать полностью рекурсивную грамматику . Неизвестно, почему для оболочки C. Возможно, это просто так, как Джой сказал в интервью в 2009 году: «Когда я начал делать это с Unix, я не был очень хорошим программистом». Специальная конструкция означала, что язык оболочки C не был полностью рекурсивным. Существовал предел сложности команды, которую он мог обработать.

Он работал для большинства интерактивно вводимых команд, но для более сложных команд, которые пользователь мог написать в сценарии, он мог легко выйти из строя, выдав только загадочное сообщение об ошибке или нежелательный результат. Например, оболочка C не может поддерживать трубопровод между управляющими структурами. Попытка трубы вывода в foreachкоманду на grepпросто не работает. (Обход, который работает для многих жалоб, связанных с синтаксическим анализатором, состоит в том, чтобы разбить код на отдельные сценарии. Если foreachсценарий перемещен в отдельный сценарий, конвейерная обработка работает, потому что сценарии запускаются путем разветвления новой копии csh который наследует правильные дескрипторы stdio.)

Другой пример - нежелательное поведение в следующих фрагментах. Оба они означают: «Если myfile не существует, создайте его, написав в нем mytext». Но версия справа всегда создает пустой файл, потому что порядок оценки оболочки C заключается в том, чтобы искать и оценивать операторы перенаправления ввода-вывода в каждой командной строке при ее чтении, прежде чем проверять остальную часть строки, чтобы увидеть, содержит ли она структура управления.

# Works as expected
if ( ! -e myfile ) then
   echo mytext > myfile
endif
# Always creates an empty file
if (! -e myfile) echo mytext > myfile
# Workaround
if (! -e myfile) eval "echo mytext > myfile"

Реализация также подвергается критике за заведомо плохие сообщения об ошибках, например, «0 событие не найдено», что не дает полезной информации о проблеме.

Оказать влияние

64-битная оболочка Hamilton C на рабочем столе Windows 7 .

Оболочка C чрезвычайно успешно внедрила большое количество нововведений, включая механизм истории , псевдонимы , нотацию тильды , интерактивное завершение имени файла, грамматику выражений, встроенную в оболочку, и многое другое, которые с тех пор были скопированы другими оболочками Unix. Но в отличие от sh , породившего большое количество независимо разработанных клонов, включая ksh и bash , известны только два клона csh . (Поскольку tcsh был основан на коде csh, первоначально написанном Биллом Джоем, он не считается клоном.)

В 1986 году Аллен Голуб написал « По команде: написание Unix-подобной оболочки для MS-DOS» , книгу, описывающую написанную им программу под названием «SH», но на самом деле скопировавшую конструкцию языка и особенности csh, а не sh. Сопутствующие дискеты, содержащие полный исходный код SH и базовый набор Unix-подобных утилит (cat, cp, grep и т. Д.), Были доступны от издателя за 25 и 30 долларов соответственно. Управляющие структуры, грамматика выражений, механизм истории и другие функции в SH Holub были идентичны таковым в оболочке C.

В 1988 году Hamilton Laboratories начала поставки оболочки Hamilton C для OS / 2 . Он включал в себя как клон csh, так и набор утилит, подобных Unix. В 1992 году Гамильтон C оболочки была выпущена для Windows NT . Версия для Windows по-прежнему активно поддерживается, но версия OS / 2 была прекращена в 2003 году. В кратком справочнике начала 1990 года цель описывалась как «полное соответствие всему языку оболочки C (кроме управления заданиями )», но с улучшениями в дизайне языка. и адаптация к различиям между Unix и ПК. Самым важным улучшением был нисходящий синтаксический анализатор, который позволял встраивать или передавать управляющие структуры по конвейеру, что не могла поддерживать исходная оболочка C, учитывая ее специальный синтаксический анализатор. Гамильтон также добавил новые языковые функции, включая встроенные и определяемые пользователем процедуры, блочные локальные переменные и арифметику с плавающей запятой. Адаптация к ПК включала поддержку имени файла и других соглашений на ПК и использование потоков вместо вилок (которые не были доступны ни в OS / 2, ни в Windows) для достижения параллелизма , например, при настройке конвейера.

Смотрите также

использованная литература

дальнейшее чтение

внешние ссылки