Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Ресурс – это абстрактная структура, имеющая множество атрибутов, характеризующих способы доступа к ресурсу и его физическое представление в системе 3 страница



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

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

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

3.3.2. Методы реализации взаимных исключений

В [1] приведены основные требования, предъявляемые к критическим секциям:

в любой момент времени только один процесс должен находиться в своей критической секции;

продолжительность нахождения процесса в критической секции не может быть бесконечно долгой;

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

процесс, работающий вне своей критической секции не должен блокировать критическую секцию другого процесса;

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

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

Эти требования могут быть реализованы множеством средств, описанных Дейкстрой в [4] ещё в 1972 г. К ним относятся:

блокировка памяти;

специальные команды типа "проверка и установка";

средства, предоставляемые системой управления прерываниями:

семафорные операции;

мониторы;

почтовые ящики, конвейеры и очереди сообщений.

3.3.3. Блокировка памяти

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

применение одной общей переменной (переключателя);

применение двух общих переменных;

применение двух общих переменных с усилением взаимных исключений;

применение трёх общих переменных (алгоритм Декера).

Применение одной общей переменной предусматривает создание переменной, называемой " переключателем " и могущей принимать значения 1 или 2. Значение переключателя равное единице разрешает выполнение секции CS1 (рис. 3.2), а значение переключателя равное двум – выполнение секции CS2. Выполнение критической секции одного процесса не блокирует выполнение обычной секции другого.

В начальный момент запуска процессов переключатель ставится в состояние единица. При этом процесс Р1 выполняет критическую секцию PS1, а процесс Р2 – секцию PR2. Отработав критическую секцию, процесс Р2 ставит переключатель в состояние двойка и переходит к выполнению обычной секции PR1. Процесс Р2 начинает выполнять критическую секцию CS2. После её завершения переключатель устанавливается в положение единица, система приходит в исходное состояние, и всё повторяется.

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

Применение двух переменных предусматривает создание двух общих для процессов Р1 и Р2 логических переменных, которые называются флагами, могут иметь значения True или False. Эти переменные называются переключателями. Далее для определённости рассмотрения реализации взаимного исключения они будут иметь имена " перекл_1 " и " перекл_2 ". Значение True флага перекл_1 означает, что процесс Р1 находится в критической секции CS1, а значение True флага перекл_2 указывает на нахождение в критической секции CS2 процесса Р2.

Перед вхождением в критическую секцию процесс Р1 проверяет состояние флага перекл_2 и, если он имеет значение False, устанавливает свой флаг перекл_1 в состояние True и начинает выполнять свою критическую секцию. После её завершения процесс восстанавливает состояние False флага перекл_1. Если перекл_2 в момент проверки находился в состоянии True, то процесс Р1 мог выполнять обычную секцию или становился в очередь ожидания разрешения на вхождение в критическую секцию. Аналогичным образом действует и процесс Р2, но для него разрешением на вхождение в критическую секцию является значение False флага перекл_1, а управляет он флагом перекл_2.

Такой алгоритм не даёт полной гарантии взаимного исключения, т.к. перевод флагов из одного состояния в другое и вхождение в критическую секцию имеют конечную длительность. За время изменения состояния флага перекл_1 процессом Р1 и вхождения в критическую секцию процесс Р2 (если он имеет более высокое быстродействие) может успеть изменить флаг перекл2 и войти в свою критическую секцию, а процесс Р1 этого не заметит. Возможна и обратная ситуация, если процесс Р1 имеет более высокое быстродействие, чем процесс Р2.

Применение двух переменных с усилением взаимного исключения предусматривает изменение алгоритма работы с переключателями перекл_1 и перекл_2. Усиление взаимного исключение для процесса Р1 сводится к перестановке операций проверки флага перекл_2 и установки флага перекл_1: сначала производится установка флага перекл_1, а после этого проверяется состояние флага перекл_2. Процесс Р2 наоборот, сначала устанавливает флаг перекл_2 и только после этого проверяет состояние флага перекл_1.

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

Алгоритм Декера предусматривает создание трёх переменных перекл_1, перекл_2 и Очередь. Переменные перекл_1 и перекл_2, как и ранее, гарантируют выполнение взаимного исключения. Переменная очередь, указывает какой из процессов, конкурирующих за критический ресурс, должен войти в свою критическую секцию. Переменная очередь не изменяется во время принятия решения о порядке вхождения процессов в критические секции. Её изменение присходит в конце выполнения критической секции. Таким образом, согласно алгоритму Деккера возможны три ситуации вхождения процессами в критические секции:

перекл_1=True и перекл_2=False;

перекл_1=False и перекл_2=True;

перекл_1=True и перекл_2=True и оба процесса желают сойти в критическую секцию.

В первой ситуации право входа в критическую секцию имеет процесс Р1 независимо от значения переменной очередь, во второй ситуации право входа в критическую секцию принадлежит процессу Р2, а в третьей право входа процессов в критическую секцию определяет значение переменной очередь.

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

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

3.3.4. Применение специальных операций
типа "проверка–установка"

Причиной возникновения проблем при реализации взаимного исключения посредством блокировки памяти является реализация механизма двумя командами "проверить флаг" и "становить флаг". Во время исполнения этой пары операций доступ к флагам имеют все процессы, конкурирующие за критический ресурс. Попытка решить эту проблему аппаратными средствами была сделана ещё в знаменитых машинах IBM 360 и IBM 370. В них появилась единая неделима команда TS (Test and Set) проверки и установки переменных. Т.к. эта команда неделима, то на время её использования одним процессом проверяемая переменная становится недоступна другим процессам.

Команда TS имеет формат:

TS (операнд_1, операнд_2).

В процессе её выполнения в операнд_1 копируется значение из операнд_2, а операнд_2 получает значение единица.

Для реализации взаимного исключения, как и в случае блокировки памяти, создаются два флага перекл_1 и перекл_2, а также переменная common. Все три переменные являются общими для конкурирующих за критический ресурс процессов. При запуске процессов Р1 и Р2 переменная common получает значение нуль. Перед вхождением в свои критические секции процессы Р1 и Р2 ставят свои флаги в состояние единица и выполняют команду TS:

процесс Р1: перекл_1:=1; TS(перекл_1,common);

процесс Р2: перекл_2:=1; TS(перекл_2,common).

В результате выполнения команды TS флаги получают значения переменной common, а переменная common – значение единица. После выполнения каждым процессом критической секции происходит установка переменной common в состояние нуль.

В архитектуре IA32 команда TS получила своё развитие, в результате которого появились три команды BTC, BTS и BTR.

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

3.3.5.Семафоры и их применение

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

Эта идея реализована в семафорных примитивах Дейкстры. Семафором называется переменная специального типа, которая доступна параллельным процессам. Для управления семафором S процессы могут использовать только две операции: "открыть" V(S) и "закрыть" P(S).

При старте процессов должна выполняться инициализация семафора, т.е. задание ему начального значения. Инициализация семафора осуществляется операцией InitSem(Имя_семафора, Начальное_состояние).

Семафор (S) является дополнительным критическим ресурсом, который указывается в качестве параметра операции, а операции P(S) и V(S) являются примитивами. Они неделимы и взаимно исключают друг друга.

Механизм семафора включается по запросу любого процесса из числа параллельных. Схема работы механизма семафора предусматривает проверку состояния ресурса, с которым связан семафор S, и в зависимости от состояния семафора допуск процесса к ресурсу или отказ в доступе к нему. При отказе в доступе процесс переводится в режим пассивного ожидания и, следовательно, не потребляет процессорное время. Разумеется, существует очередь ожидающих процессов. Средства обслуживания очереди входят в механизм семафорного процесса и реализуются супервизором операционной системы. Вследствие взаимного исключения примитивов P(S) и V(S) попытка одновременного выполнения примитивов несколькими разными процессами приведёт к тому, что только один из них успешно выполнит примитив, т.е. будет выполнено взаимное исключение процессов.

В настоящее время существует достаточно много семафорных механизмов, описанных в [5] и различающихся следующими параметрами:

· начальное значение семафора;

· диапазон допустимых значений семафора;

· логика действий семафорных операций;

· количество семафоров, доступных примитивам для обработки.

Различают семафоры с разным числом состояний. Существуют двоичные семафоры, имеющие два состояния: "открыт" и "закрыт". Такие семафоры называются мьютексами. Существуют семафоры, имеющие N состояний. Среди них различают семафоры столько положительными значениями и семафоры, допускающие отрицательные значения. В таких семафорах отрицательные значения указывают длину очереди процессов, ожидающих критический ресурс.

Два варианта реализации семафора показаны на рис. 3.4. В обоих случаях описания примитивов можно оформит в виде процедур или процедур-функций. Примитив P(S) вызывается процессом перед вхождением в критическую секцию. Примитив V(S) вызывается после выполнения критической секции.

В варианте рис. 3.4,а примитив P(S) сразу уменьшает значение семафора на единицу и, если новое значение семафора меньше нуля операцией WAIT(S) останавливает процесс и помещает его в очередь ожидания к семафору S. В варианте рис. 3.4,б сначала проверяется значение семафора и, если оно не меньше единицы, то значение семафора уменьшается на единицу. В противном случае операцией WAIT(S) процесс останавливается и помещается в очередь ожидания к семафору.

P(S): S:=S-1; If S<0 Then WAIT(S)

V(S): If S<0 Then RELEASE(S); S:=S+1

а)

P(S): If S>=1 Then S:=S-1 Else WAIT(S)

V(S): If S<0 Then RELEASE(S); S:=S+1

б)

Рис. 3.4. Неудачный (а) и удачный (б) варианты реализации примитивов P(S) и V(S)

Примитив V(S) в обоих вариантах проверяет значение семафора S и если оно меньше нуля, то операцией RELEASE(S) ставит один из ожидающих семафор процессов в очередь готовности. Перед завершением обработки семафора примитив увеличивает значение семафора на единицу.

Применение обоих вариантов реализации семафоров можно проиллюстрировать программным кодом, показанным на рис. 3.5.

Var S: Semafor Begin InitSem(S,1) {описание переменной S типа Semafor} {начало программного кода} {инициализация семафора S значением единица}
Parbegin {начало описания параллельных процессов}
while true do {организация бесконечного процесса Р1 }
begin P(S) CS1 V(S) end {начало описания тела процесса Р1} {вызов примитива P(S)} {выполнение критической секции процесса Р1} {вызов примитива V(S)} {конец описания тела процесса Р1}
AND {разделитель описаний процессов }
while true do {организация бесконечного процесса Р2 }
begin P(S) CS1 V(S) end {начало описания тела процесса Р2} {вызов примитива P(S)} {выполнение критической секции процесса Р2} {вызов примитива V(S)} {конец описания тела процесса Р2}
Parend {конец описания параллельных процессов}
End {конец программного кода}

Рис. 3.5. Пример применения семафора

Один и тот же программный код (рис. 3.5) при использовании разных вариантов реализации семафора даст разный результат. Вариант реализации, показанный на рис. 3.4,б, будет надёжно работать, тогда как вариант рис. 3.4,а приведёт к ситуации, в которой заблокированы оба процесса (рис. 3.6.).


Рис. 3.6. Возникновение ситуации блокирования обоих процессов

Эта ситуация может возникнуть следующим образом. При запуске процессов Р1 и Р2 в семафор записана (+1). Оба процесса находятся в состоянии готовности. В момент времени t1 примитив P(S), вызванный процессом Р1 сбросит семафор в нуль. Во время выполнении критической секции CS1 процесса Р1 значение семафора равно нулю.

Однако в момент t2 примитив P(S), вызванный процессом Р2 запишет в семафор значение (-1), а сам процесс Р2 будет остановлен. В момент t3 примитив V(S) восстановит в семафоре значение ноль и переведет процесс Р2 в состояние готовности. Процесс Р1 останется в состоянии готовности.

Если Р2 попытается войти в свою критическую секцию, то это ему не удастся. В момент времени t4 в семафоре будет восстановлено значение (-1), процес Р2 будет остановлен и поставлен в очередь к семафору. Дальнейшая попытка процесса Р1 войти в свою критическую секцию будет также неудачна, процесс Р1 будет остановлен, и возникнет ситуация блокирования обоих процессов, из которой выхода нет.

Реализация неделимости примитивов P(S) и V(S) в однопроцессорной системе достигается простым отключением прерываний в критических секциях процессов и их последующим включением при выходе из неё. В многопроцессорных системах этот вариант не проходит, т.к. не запрещает одновременный запрос критического ресурса со стороны множества процессоров. Поэтому механизм семафоров несколько усложняется и дополняется аппаратной поддержкой взаимного исключения доступа для разных процессоров. Это может быть достигнуто, например, использованием неделимых команд "проверка – установка" TS, которые описаны в 3.3.4.

Некоторые особенности имеет применение двоичных семафоров (мьютексов). Они имеют два состояния "отмечен" (открыт) и "не отмечен" (закрыт). Мьютексы предназначены для организации взаимного исключения для потоков выполнения (задач) одного или нескольких процессов.

В любой момент времени мьютекс может принадлежать только одной задаче или не принадлежать ни одной из задач. Задача, захватившая мьютекс, снимает пометку и закрывает семафор. При освобождении мьютекса задача восстанавливает пометку, т.е. открывает семафор. Важнейшим свойством мьютекса является его имя, которое используется задачами для захвата в целях применения. При организации последовательного доступа к ресурсам с помощью мьютексов не возникает никаких затруднений. Для организации использования задачами разных процессов имя мьютекса должно передаваться по наследству" от одной задачи к другой.

Для работы с мьютексами используются системные вызовы (функции):

CreateMutex() – создание мьютекса;

OpenMutex() – открытие мьютекса;

WaitForSingleObject() – ожидание события от одного объекта;

WaitForMultipleObject() – ожидание события от множества объектов;

ReleaseMutex() – освобождение мьютексм.

3.3.6. Мониторы

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

Более лучшее решение вопроса о взаимном исключении в 80-х гг. прошлого века предложил Ч. Хоар. Он предложил механизм мониторов. Монитором в параллельном программировании называют пассивный набор разделяемых переменных и повторно входимых процедур (см. раздел 1.6). Повторно входимые процедуры обеспечивают доступ к разделяемым переменным. В каждый момент времени монитором может пользоваться только один процесс. Процедуры монитора исполняются только по требованию процессов.

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

Пример реализации простейшего монитора для выделения процессам одного ресурса показан на рис. 3.7 [1].

monitor Resource; condition free; var busy: boolean; {заголовок описания монитора} {условие ожидания – свободный} {описание переменной занят}
Procedure REQUAEST; begin if busy then WAIT(free);   busy:=True; TakeOff end; {заголовок процедуры Запрос ресурса}   {если монитор занят, то блокировать вызвавший} {процесс до сигнала Свободен} {перевод монитора в состояние Занят} {предоставить ресурс ожидающему процессу}  
Procedure RELEASE; begin TakeOn; busy:=False; SIGNAL(free); end; {заголовок процедуры Освободить ресурс}   {взять предоставленный ресурс} {освободить монитор} {послать сигнал Свободен ожидающим процессам}

Рис. 3.7. Пример реализации простейшего монитора

Исполняющийся процесс запрашивает ресурс, вызывая процедуру REQUAEST. Если монитор занят (busy:=True), то процесс блокируется и ставится в очередь ожидания. Дальнейшее выполнение процедуры откладывается. Если монитор свободен, то он переводится в состояние "Занят" и предоставляет критический ресурс вызвавшему REQUAEST процессу.

Процесс, использующий ресурс, вызывает процедуру RELEASE, забирает его в своё пользование. Использовав ресурс, процесс переводит монитор в состояние "Свободен" и подаёт сигнал "Свободен" ожидающим процессам. Рано или поздно очередь пользования ресурсом дойдёт до отложенного процесса, по сигналу "Свободен" он снова сделает попытку вызывать REQUAEST и, в конце концов, получит в своё распоряжение критический ресурс.

По сравнению с семафорами мониторы имеют следующие преимущества:

· высокая гибкость, т.е. способность мониторов приспосабливаться к новым задачам;

· локализация разделяемых переменных и процедур внутри тела монитора, что позволит не применять сложные малопонятные конструкции в синхронизируемых процессах;

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

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

3.3.7. Почтовые ящики, конвейеры и очереди сообщений

Указанные в заголовке объекты являются средствами организации обмена данными между взаимодействующими процессами. На рис. 3.2 показана обобщённая модель взаимодействия параллельных процессов. Сотрудничающие процессы могут обмениваться данными через общую область памяти.

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

Множество буферов сообщений (гнёзд), предназначенных для одного процесса, называются почтовым ящиком. Почтовый ящик является информационной структурой и состоит из головного элемента и нескольких гнёзд. Головной элемент содержит сведения о почтовом ящике (количество гнёзд и их объёмы), которые задаются при создании почтового ящика.

Для работы с почтовым ящиком используются системные функции:

SAND_MASSAGE(Получатель, сообщение, буфер) – копирование сообщения в буфер, запись адреса буфера в переменную Буфер, добавление буфера в очередь к получателю;

WAIT_MASSAGE(Отправитель, Сообщение, Буфер) – блокирование процесса, запросившего сообщение до появления сообщения в его очереди; при передаче процесса на исполнение процессором он получает имя отправителя, текст сообщения и адрес буфера через переменные, указанные в списке параметров), затем буфер удаляется из очереди, а процесс может записать в него свой ответ отправителю;

SAND_ANSWER(Результат, Ответ, Буфер) – запись информации, определённой переменной Ответ в буфер, указанный переменной Буфер; переменная Результат указывает является ли ответ пустым или нет;

WAIT_ANSWER(Результат, Ответ, Буфер) – блокирование процесса, вызвавшего функцию до появления в его буфере какого-либо ответа; переменная результат указывает, является ли ответ пустым или нет, переменная Ответ получает ответ, переменная Буфер указывает адрес буфера, содержащего ответ; при передаче процесса на выполнение на процессоре, процесс получает ответ, а буфер очищается.

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

В зависимости от длины сообщений существует множество вариантов использования почтовых ящиков.

Почтовые ящики как средство организации обмена данными между процессами имею следующие достоинства:

процессу нет надобности знать о других процессах до получения от них сообщений;

два процесса могут обменяться несколькими сообщениями за один раз;

операционная система гарантирует невмешательство в обмен сообщениями и ответами процессов, не имеющих к нему никакого отношения;

вследствие существования очередей буферов работа процессов-отправи­телей сообщений не зависит от процессов-получателей.

Недостатками почтовых ящиков являются:

появление дополнительных ресурсов, подлежащих управлению, которыми являются сами почтовые ящики;

статический характер почтовых ящиков.

Конвейеры, иначе транспортёры или каналы связи, представляют собой потоки байтов, передающихся между двумя и более процессами. Физически конвейеры реализуются как буферная память, работающая по принципу FIFO, но они не являются очередями. Как информационная структура конвейеры описываются идентификатором, размером (не более 64К), указателем начала данных и указателем конца данных, которые определяют адреса начала и конца данных. Конвейер представляет собой закольцованную очередь (рис. 3.8).

В исходном состоянии оба указателя равны нулю. При добавлении в конвейер данных оба указателя увеличиваются на единицу. Дальнейшее добавление данных увеличивает значение указателя на конец данных (рис. 3.8,а). Чтение и удаление данных происходит всегда с начала. Поэтому при чтении и удалении данных приходится изменять значения указателей. В итоге указатели движутся от начала конвейера к её концу. Серым цветом на рис. 3.8 показаны записанные данные. Свободная область в начале конвейера образовалась в результате удаления и чтения данных.

  а)
       
 
   
 



б)

Рис. 3.8. Принцип действия конвейера

При достижении указателем конца данных правой границы конвейера дальнейшая запись будет происходить в левую свободную часть конвейера. Указатель на конец данных переместится сначала на левую границу конвейера, а затем начнёт перемещаться вправо, Левая свободная область будет "вытеснять" данные вправо вместе с указателем начала данных (рис. 3.8,б).

Разумеется, читать данные из конвейера может только тот процесс, который "знает" идентификатор конвейера. Недостатком конвейера является ограничение его ёмкости 64 К, что ограничивает размер передаваемых сообщений.





Дата публикования: 2014-11-18; Прочитано: 297 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.027 с)...