Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > Взаимодействие параллельных процессов (алгоритм)


Автор: phprus 18.2.2010, 16:34
Есть такое дерево процессов:
Код

Base
 |_A

По запросу процесса А, процесс Base порождает новый процесс В:
Код

Base
 |_A
 |_B

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

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

Заранее благодарен за помощь в придумывании алгоритма взаимодействия.

Автор: InvalidProperty 18.2.2010, 16:47
в передающем процессе передавай длину сообщения первым двойным словом, затем будет располагаться само сообщение. После формирования такого пакета, посылай сигнал в получающий процесс, принимающий процесс должен заснуть до получения сигнала об успешном получении пакета. Затем цикл повторяется

Автор: phprus 18.2.2010, 17:12
InvalidProperty, спасибо за идею с сигналами. Подумаю, как ее можно применить.

Но все-же хотелось бы реализовать задачу на более классических средствах синхронизации (чем sleep() & kill()), как более понятных что-ли. Да и сигналы асинхронны, а очень хотелось бы собрать весь код получения (в процессе А) в одном месте и вообще на время передачи блокировать цикл обработки событий, так как если эта передача начата, но не закончена, то какие-либо другие действия бессмысленны (по общей логике программы).

Автор: InvalidProperty 18.2.2010, 17:28
phprus, а почему бы не использовать библиотеку pthread, т.е. потоки?

Автор: phprus 18.2.2010, 23:31
InvalidProperty, Там много мегабайт кода на С, под несколько платформ и что-бы не углубляться во все эти дебри реализации я и интересуюсь возможным алгоритмом. По этому и не получится использовать потоки. Да и чем они по сути будут отличаться? Только одним адресным пространством, а синхронизироваться все так-же придется.

Кажется у меня появилась мысль, как реализовать эту синхронизацию на двух mutex'ах, основываясь на предположении, что процесс генератор данных гарантированно может сделать что-либо (например получить/снять блокировку) раньше, чем читающий процесс войдет в функцию чтения (из-за того, что функция чтения запуститься только после получения соответствующего уведомления от процесса генератора данных). Завтра попробую ее обдумать и реализовать.

Автор: svlary 19.2.2010, 06:27
Цитата

возможно ли в таком случае обеспечить передачу данных без возможных гонок за доступ к памяти?

   Не могу понять - а почему в таком ПРОСТОМ случае нужна разделяемая память, мьютексы, треды, семафоры и прочая галиматья ?!  Что мешает воспользоваться самым простым и надежным механизмом - pipe ?! 
  • Обмен идет между родственными процессами, поэтому передать файловый дескриптор - никаких проблем.
  • Не надо думать о распределении памяти, операционка об этом сама позаботиться.
  • Нет никаких проблем с синхронизацией - процесс-потребитель просто ждет завершения read(...)
  Ну и так дале... Принцип KISS...  smile 

Автор: phprus 19.2.2010, 20:35
Цитата(svlary @  19.2.2010,  09:27 Найти цитируемый пост)
Обмен идет между родственными процессами, поэтому передать файловый дескриптор - никаких проблем.

Нет fork'а. Такой странный метод порождения процессов возник как раз из-за этого (Windows одна из возможных платформ).
Да и в *NIX не меняя кода процесса Base и не вводя в него логику по созданию pipe и проксировании данных между А и В воспользоваться pipe не получится. Процессы А, В - братья, а не родитель/ребенок.

Автор: svlary 24.2.2010, 08:22
Цитата

Процессы А, В - братья, а не родитель/ребенок

сопоставив с 
Цитата

не меняя кода процесса Base

  Я понял так, что у Вас нет возможности модифицировать код родительского процесса. Но и тут можно обойтись без разделяемой памяти :
  • Именованые каналы.
  • UNIX-сокеты
  • Системные очереди сообщений в смысле POSIX или System-V
  В любом случае, я твердо убежден, что использование разделяемой памяти, семафоров, мьютексов и т.д. - самое неудачное проектное решение в силу своей запутанности и ненадежности.

Автор: phprus 24.2.2010, 13:46
Всем спасибо за ответы, при решении задачи мне помогли материалы http://ru.sun.com/research/materials/Irtegov_Tech.jsp (Лекция 7. Блокировки чтения-записи...)


Цитата(svlary @  24.2.2010,  11:22 Найти цитируемый пост)
В любом случае, я твердо убежден, что использование разделяемой памяти, семафоров, мьютексов и т.д. - самое неудачное проектное решение в силу своей запутанности и ненадежности. 

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

Автор: svlary 25.2.2010, 06:30
Цитата(phprus @  24.2.2010,  13:46 Найти цитируемый пост)
А в чем его ненадежность?
  • В том, что вы сами должны следить за состоянием буферов - указатели, переполнение, семафоры и т.д.
  • Если же Вы используете именованые каналы, то все это делает за Вас операционная система, котрая прячется
     за системными вызовами write / read.
  • Если Вы используете системные очереди сообщений, то вся эта работа опять-таки
     делается операционкой, спрятавшейся за системными вызовами msgsnd / msgrcv.
  • Как говориться, вольному - воля! И если Вы твердо уверены в своей абсолютной непогрешимости, то вполне можно делать за
     операционку то, что обязана делать она! smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)