взаимодействие двух программ
Можно ли обойтись без файла, т.е. в идеале программа P1 передает результат программе P2 и та сразу выводит этот результат на экран?
Есть две программы: P1 и P2. P1 выполняет какие-то действия и результат записывает в файл F1. P2 через некоторые интервалы времени читает из файла F1 записанное ранее значение и выводит его на экран.
Можно ли обойтись без файла, т.е. в идеале программа P1 передает результат программе P2 и та сразу выводит этот результат на экран?
Существует много методов взаимодействия между процессами. Вот что пишет MSDN по этому поводу:
Interprocess Communications
The Microsoft® Windows® operating system provides mechanisms for facilitating communications and data sharing between applications. Collectively, the activities enabled by these mechanisms are called interprocess communications (IPC). Some forms of IPC facilitate the division of labor among several specialized processes. Other forms of IPC facilitate the division of labor among computers on a network.
Typically, applications can use IPC categorized as clients or servers. A client is an application or a process that requests a service from some other application or process. A server is an application or a process that responds to a client request. Many applications act as both a client and a server, depending on the situation. For example, a word processing application might act as a client in requesting a summary table of manufacturing costs from a spreadsheet application acting as a server. The spreadsheet application, in turn, might act as a client in requesting the latest inventory levels from an automated inventory control application.
After you decide that your application would benefit from IPC, you must decide which of the available IPC methods to use. It is likely that an application will use several IPC mechanisms. The answers to these questions determine whether an application can benefit by using one or more IPC mechanisms.
Should the application be able to communicate with other applications running on other computers on a network, or is it sufficient for the application to communicate only with applications on the local computer?
Should the application be able to communicate with applications running on other computers that may be running under different operating systems (such as 16-bit Windows or UNIX)?
Should the user of the application have to choose the other application(s) with which the application communicates, or can the application implicitly find its cooperating partners?
Should the application communicate with many different applications in a general way, such as allowing cut and paste operations with any other application, or should its communications requirements be limited to a restricted set of interactions with specific other applications?
Is performance a critical aspect of the application? All IPC mechanisms include some amount of overhead.
Should the application be a GUI application or a console application? Some IPC mechanisms require a GUI application.
The following IPC mechanisms are supported by Windows:
Clipboard
COM
Data Copy
DDE
File Mapping
Mailslots
Pipes
RPC
Windows Sockets
The following IPC mechanisms are supported by Windows:
Clipboard
COM
Data Copy
DDE
File Mapping
Mailslots
Pipes
RPC
Windows Sockets
С помощью SendMessage/PostMessage уведомляем процесс о поступлении новых данных, а сами данные размещаем в проецируемом в память файле. Такова обычная схема взаимодействия процессов, всё достаточно просто и красиво.
С помощью SendMessage/PostMessage уведомляем процесс о поступлении новых данных, а сами данные размещаем в проецируемом в память файле. Такова обычная схема взаимодействия процессов, всё достаточно просто и красиво.
SendMessage/PostMessage - некрасиво, т.к. механизм обмена данными привязывается к механизму оконных сообщений, который сам по себе не быстрый.
Лучше использовать глобальные объекты синхронизации или уже готовые механизмы типа pipes.
SendMessage/PostMessage - некрасиво, т.к. механизм обмена данными привязывается к механизму оконных сообщений, который сам по себе не быстрый.
Лучше использовать глобальные объекты синхронизации или уже готовые механизмы типа pipes.
Ну, глобальные объекты синхронизации потребуют выделения отдельного потока для отображения результатов, даже если это всего десяток операций. А вот именованные пайпы - это тема, хотя я лично предпочитаю file mapping, поскольку могу обратится к любому участку разделяемых данных в любой момент времени.
Ну, глобальные объекты синхронизации потребуют выделения отдельного потока для отображения результатов, даже если это всего десяток операций.
Зачем?!!
А вот именованные пайпы - это тема, хотя я лично предпочитаю file mapping, поскольку могу обратится к любому участку разделяемых данных в любой момент времени.
pipe - это тот же FM + глоб. объект синхронизации
Зачем?!!
Ну так ожидать-то объект нужно будет с помощью Wait-функции, а основной поток тормозить нецелесообразно.
pipe - это тот же FM + глоб. объект синхронизации
Хоккей, твоя правда. Не часто с ними работаю.
Ну так ожидать-то объект нужно будет с помощью Wait-функции, а основной поток тормозить нецелесообразно.
Так и не надо тормозить. Проверили и пошли дальше по условию: изменилось или нет состояние оъекта синхронизации.
Так и не надо тормозить. Проверили и пошли дальше по условию: изменилось или нет состояние оъекта синхронизации.
И так до тех пор, пока состояние не изменится? Тогда, на мой взгляд, проще использовать сообщения.
И так до тех пор, пока состояние не изменится? Тогда, на мой взгляд, проще использовать сообщения.
Возможно проще, но не лучше, т.к. сообщения находятся в очереди, если очередь заполнится сообщениями, то встанет не только UI, но и бизнес-логика.
Возможно проще, но не лучше, т.к. сообщения находятся в очереди, если очередь заполнится сообщениями, то встанет не только UI, но и бизнес-логика.
Не надо всё так усложнять. В данном случае основные расчёты производит уведомляющий процесс, а другой процесс просто подбирает за ним результаты. Я полагаю, что расчёт (хотя бы даже и в среднем) одной порции данных занимает гораздо больше времени, чем вывод её на экран. А если так, то, в принципе, можно сообщения посылать с ожиданием завершения отображения результатов, тогда переполняться ничего не будет (если уж так страшно :)). При использовании глобальных объектов синхронизации точно так же будут ситуации, когда процессы (точнее даже, потоки из обоих процессов) будут выполняться попеременно, ожидая друг друга.
Для несложной задачи имеем несложное решение. Рихтер, например, использовал пользовательские сообщения в качестве одной из составляющих механизма обмена данными между процессами/потоками в очень большом количестве своих примеров, и, при этом, называл их достаточным решением для простых задач из данной области.
Не надо всё так усложнять.
IMHO глобальная синхронизация даже проще :)
При использовании глобальных объектов синхронизации точно так же будут ситуации, когда процессы (точнее даже, потоки из обоих процессов) будут выполняться попеременно, ожидая друг друга.
Одно дело, когда они ждут конкретного события синхронизации, а другое дело, когда они раскручивают очередь сообщений UI и между прочим еще и получают через эту очередь сообщения синхронизации. Другими словами выставляя объект синхронизации мы уверены, что другой процесс получит этот сигнал, как только обратиться к этому объекту синхронизации. А передавая сигнал синхронизации через очередь оконных сообщений мы ждем пока процесс-получатель раскрутит очередь до этого сообщения, а этого кстати, может так и не произойти, еслу в очередь попадут сообщения с более высоким приоритетом.
Для несложной задачи имеем несложное решение. Рихтер, например, использовал пользовательские сообщения в качестве одной из составляющих механизма обмена данными между процессами/потоками в очень большом количестве своих примеров, и, при этом, называл их достаточным решением для простых задач из данной области.
В данном случае довольно корявое решение ещё по тому, что имея объект синхронизации мы чередуем владение общим ресурсом, как эстафетной палочкой. Передавая оконное сообщение, чередование становится неоднозначным, а само явление владения неопределенным. Ну и соотв-но начинаются вопросы - кто инициирует передачу и создает глобальный ресурс, кто уничтожает. Одной из проблем возникает неопределенность при завершении одной из программ: сообщение о закрытии окна придет раньше, чем сообщение о доступности ресурса, т.о. приложение завершится, неуведомив другое, что ресурс свободен.
Одно дело, когда они ждут конкретного события синхронизации, а другое дело, когда они раскручивают очередь сообщений UI и между прочим еще и получают через эту очередь сообщения синхронизации. Другими словами выставляя объект синхронизации мы уверены, что другой процесс получит этот сигнал, как только обратиться к этому объекту синхронизации. А передавая сигнал синхронизации через очередь оконных сообщений мы ждем пока процесс-получатель раскрутит очередь до этого сообщения, а этого кстати, может так и не произойти, еслу в очередь попадут сообщения с более высоким приоритетом.
Одинаково приятно, поскольку так или иначе уведомляющий процесс будет ждать завершения вывода на экран в другом процессе, который, в свою очередь, будет происходить через механизм сообщений. Так что раскрутка будет и в том, и в другом случае.
В данном случае довольно корявое решение ещё по тому, что имея объект синхронизации мы чередуем владение общим ресурсом, как эстафетной палочкой. Передавая оконное сообщение, чередование становится неоднозначным, а само явление владения неопределенным. Ну и соотв-но начинаются вопросы - кто инициирует передачу и создает глобальный ресурс, кто уничтожает. Одной из проблем возникает неопределенность при завершении одной из программ: сообщение о закрытии окна придет раньше, чем сообщение о доступности ресурса, т.о. приложение завершится, неуведомив другое, что ресурс свободен.
Не вижу причин для возникновения подобных проблем. В случае нотификации с помощью сообщений общий ресурс должен создавать/удалять уведомляющий процесс. Если он завершится раньше, чем уведомляемый, то просто отправит перед выходом соответствующее сообщение в синхронном режиме, и никакие данные не потеряются. Если раньше завершится уведомляемый процесс, то SendMessage при обращении к несуществующему окну завершится неудачей и возвратит 0. То есть, достаточно при успешном выводе на экран возвращать в обработчике ненулевое значение, и всё будет в шоколаде. Корявого, на мой взгляд, здесь ничего нет.
Одинаково приятно, поскольку так или иначе уведомляющий процесс будет ждать завершения вывода на экран в другом процессе, который, в свою очередь, будет происходить через механизм сообщений. Так что раскрутка будет и в том, и в другом случае.
Так а зачем ждать окончания вывода на экран?
Не вижу причин для возникновения подобных проблем. В случае нотификации с помощью сообщений общий ресурс должен создавать/удалять уведомляющий процесс. Если он завершится раньше, чем уведомляемый, то просто отправит перед выходом соответствующее сообщение в синхронном режиме, и никакие данные не потеряются. Если раньше завершится уведомляемый процесс, то SendMessage при обращении к несуществующему окну завершится неудачей и возвратит 0. То есть, достаточно при успешном выводе на экран возвращать в обработчике ненулевое значение, и всё будет в шоколаде. Корявого, на мой взгляд, здесь ничего нет.
1. Как понять, что общий ресурс создан?
2. Кроме того ресурс не может сам ничего создавать, его самого выделяют и пользуют.
P1 <-данные-> Shared <-данные-> P2
3. Как P1 поймет, кому передавать сообщения? FindWindow? Как-то ненадежно...
4. Рассмотрим такую ситуацию: P1 заполнил общий ресурс данными и послал уведомление P2, которое встало в очередь сообщений. Теперь P1 ждет уведомления от P2 об окончании обработки переданных данных. Но в процессе раскрутки очереди сообщений в P2, поступает сообщение WM_CLOSE (WM_DESTROY), которое более приоритетно, чем наше сообщение синхронизации. В результате P2 скоропостижно скончалось, не успев уведомить P1, которое теперь вечно будет ждать сообщения от почившего P2.
Заставить P2 перед смертью уведомлять родных и близких о своей кончине? Не усложняется ли при этом "несложное решение для несложной задачи".
А если P2 скончается в результате несчастного случая? Кто распорядится наследством?
Так а зачем ждать окончания вывода на экран?
К примеру, SetWindowText() отсылает элементу управления сообщение WM_SETTEXT в синхронном режиме. Иметь в нашем случае две копии данных (одна - защищённая, другая - локальная для процесса и используется для отсылки сообщений элементам управления), на мой взгляд, нерационально.
1. Как понять, что общий ресурс создан?
Если поступило сообщение о возникновении новых данных, то ресурс уже создан (естесственно, если ресурс создан уведомляющим процессом)
2. Кроме того ресурс не может сам ничего создавать, его самого выделяют и пользуют.
Во фразе
подлежащим является слово "процесс" (sorry, если выразился неоднозначно)
P1 <-данные-> Shared <-данные-> P2
3. Как P1 поймет, кому передавать сообщения? FindWindow?
Не обязательно. Процесс, выводящий данные на экран, может один раз уведомить о своём присутствии тем или иным способом (например, с помощью тех же сообщений). Я могу задать вопрос из той же серии: предположим, что запущено два процесса, генерирующих нужные нам данные (возможно даже, пользователь случайно тыкнул кнопкой лишний раз). Как, при использовании объектов синхронизации, программа, которая выводит результаты, узнает, какой из процессов ей эти данные предоставил?
4. Рассмотрим такую ситуацию: P1 заполнил общий ресурс данными и послал уведомление P2, которое встало в очередь сообщений. Теперь P1 ждет уведомления от P2 об окончании обработки переданных данных. Но в процессе раскрутки очереди сообщений в P2, поступает сообщение WM_CLOSE (WM_DESTROY), которое более приоритетно, чем наше сообщение синхронизации. В результате P2 скоропостижно скончалось, не успев уведомить P1, которое теперь вечно будет ждать сообщения от почившего P2.
Заставить P2 перед смертью уведомлять родных и близких о своей кончине? Не усложняется ли при этом "несложное решение для несложной задачи".
А если P2 скончается в результате несчастного случая? Кто распорядится наследством?
Опять усложняешь? Взаимный обмен сообщениями в нашем случае необязателен, уведомляющий процесс может отсылать сообщения в синхронном режиме (то есть, с помощью SendMessage). Если ресурс создаётся уведомляющим процессом, то другой процесс обрабатывать его уничтожение не обязан, на его работу это не повлияет (он обращается к разделяемым данным только при обработке соответствующего сообщения). WM_CLOSE не будет обработано до тех пор, пока обработчик нашего сообщения не возвратит управление (естесственно, если на этот момент наше уведомляющее сообщение уже обрабатывается, в противном случае, как я уже говорил, SendMessage вернёт 0).
Я могу задать вопрос из той же серии: предположим, что запущено два процесса, генерирующих нужные нам данные (возможно даже, пользователь случайно тыкнул кнопкой лишний раз). Как, при использовании объектов синхронизации, программа, которая выводит результаты, узнает, какой из процессов ей эти данные предоставил?
если проги генерирующие данные по определению две и это определено архитектурно то можно как миниум использовать два разных объекта синхронизации. случайный же запуск двух прог генерирующих данные должен быть исключен с помощью соответствующих методов. Так как в этом случае архитектурно прога генерериующая данные - одна.
если проги генерирующие данные по определению две и это определено архитектурно то можно как миниум использовать два разных объекта синхронизации. случайный же запуск двух прог генерирующих данные должен быть исключен с помощью соответствующих методов. Так как в этом случае архитектурно прога генерериующая данные - одна.
Ну, если каждая программа запущена лишь в одном экземпляре (по определению), то даже FindWindow выглядит не так уж ненадёжно (хотя хорошим механизмом её не назовёшь).
Я могу задать вопрос из той же серии: предположим, что запущено два процесса, генерирующих нужные нам данные (возможно даже, пользователь случайно тыкнул кнопкой лишний раз). Как, при использовании объектов синхронизации, программа, которая выводит результаты, узнает, какой из процессов ей эти данные предоставил?
Если источник должен быть один, то это обеспечивается все теми же объектами синхронизации. Если - несколько, то здесь нужен либо механизм соответствия, что несложно, либо просто неименованые pipes, только тогда P2 должен быть порожден от P1.
Взаимный обмен сообщениями в нашем случае необязателен, уведомляющий процесс может отсылать сообщения в синхронном режиме (то есть, с помощью SendMessage).
Т.о. мы получаем жесткую синхронную связь двух процессов: один будет постоянно ждать другого?
Т.о. мы получаем жесткую синхронную связь двух процессов: один будет постоянно ждать другого?
Как я уже говорил, в нашем случае такое ожидание всё равно будет иметь место, так что потеря производительности, на мой взгляд, здесь будет невелика (конечно, можно найти подход, позволяющий не ожидать завершения вывода на экран полностью, но это, на мой взгляд, излишне усложнит задачу).
Здесь нужен механизм соответствия
А можно поподробнее о таком механизме? В чём он будет заключаться?
Либо просто неименованые pipes, только тогда P2 должен быть порожден от P1.
Ну, тут уже у автора надо спросить, каким образом он запускает каждый из процессов. Если один из них порождает другой, то решение задачи в любом случае упростится.
Ну, тут уже у автора надо спросить, каким образом он запускает каждый из процессов. Если один из них порождает другой, то решение задачи в любом случае упростится.
Нет, первый процесс не порождает второй. Пока у меня вроде бы все получается. Огромное спасибо всем за помощь.
Есть следующий код для клиента:
LPTSTR lpszPipename = "\\\\.\\pipe\\kolTelN";
HANDLE hPipe;
WaitNamedPipe(lpszPipename, NMPWAIT_WAIT_FOREVER);
hPipe = CreateFile(lpszPipename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if (hPipe == INVALID_HANDLE_VALUE)
MessageBox(0, "Invalid handle value1", NULL, MB_OK);
DWORD bytesWrt;
unsigned char kolTelN=i+1;
int res = WriteFile( hPipe, &kolTelN, 1, &bytesWrt, NULL );
if(!res)
MessageBox(0, "Can't write to file", NULL, MB_OK);
CloseHandle(hPipe);
Насколько я понял, строка:
WaitNamedPipe(lpszPipename, NMPWAIT_WAIT_FOREVER);
заставляет клиента ждать пока сервер не создаст Pipe с таким именем. Но клиент не ждет а выполняет следующие операции и из-за этого возникают глюки (и переменная hPipe =INVALID_HANDLE_VALUE и res = 0 и т.д.). Как это исправить? Или я плохо разобрался с принципом работы Pipes?