Взаимодействие между процессами
В одном процессе выделяем память, пишем в нее нужную информацию. Затем запускаем другой процесс и через командную строку (или через ::PostMessage или ::SendMessage) передаем указатель (дескриптор) выделенной памяти. Далее запущенный процесс должен обработать переданные ему данные и корректно освободить память.
Пробовал сделать через ::GlobalAlloc - ничего не вышло (в другом процессе GetLastError возвращал Invalid Handle), далее прочитал в MSDN, что функция GlobalAlloc - то же самое, что и в LocalAlloc (они различались только в 16-ти разрядных Windows). Отсюда сделал вывод, что GlobalAlloc мне не поможет.
Кто нибудь знает стандартный способ реализации указанного выше поведения? (мне не нужно через ClipBoard, temporary file, regestry, мне нужно только через память).
Всем спасибо за помощь. Сам разобрался через сообщение ::SendMessage(..., WM_COPYDATA, ...)
Неэффективно.
Используй Shared memory (Memory Mapped File).
Неэффективно.
Используй Shared memory (Memory Mapped File).
Хм, что значит не эффективно? Объем передаваемых мною данных примерно 20 - 50 байт.
Думаете, что для данной задачи эффективнее использовать File Mapping? А может лучше создать anonymous pipe, или подключать OLE\ActiveX контейнеры, или пользоваться почтовыми слотами (mailslots) для межпроцессного взаимодействия?
Стоят ли эти 20-50 байт таких накладных расходов?
Я все-таки считаю, что каждый способ по своему эффективен.
Хм, что значит не эффективно? Объем передаваемых мною данных примерно 20 - 50 байт.
Думаете, что для данной задачи эффективнее использовать File Mapping? А может лучше создать anonymous pipe, или подключать OLE\ActiveX контейнеры, или пользоваться почтовыми слотами (mailslots) для межпроцессного взаимодействия?
Стоят ли эти 20-50 байт таких накладных расходов?
Я все-таки считаю, что каждый способ по своему эффективен.
Сарказм здесь неуместен.
1. Через anonymous pipe передать информацию между процессами, непорожденными друг от друга или от одного процесса, неполучится.
2. Pipe, mailslots основанны на все тех же Memory Mapped Files.
3. При чем тут OLE\ActiveX контейнеры я вообще не понял.
При использовании WM_COPYDATA придется создать окно (ведь окна в приложении может и не быть), ставить в очередь сообщений и выбирать из нее это оконное сообщение, а работа с очередью сообщений весьма тормознутый процесс. При этом система будет копировать информацию из одного адресного пространства в другое. Ну а уж о проблеме защиты и целостности информации я уж и не говорю.
Так что вариант с WM_COPYDATA более накладен с точки зрения ресурсов (производительность, память). А уж надежность вообще никакая. Единственный плюс - простота реализации для новичков.
Сарказм здесь неуместен.
Это точно. Сарказм везде неуместен. Но и тебе,IMHO, нужно быть менее категоричным.
1. Через anonymous pipe передать информацию между процессами, непорожденными друг от друга или от одного процесса, неполучится.
Это факт.
2. Pipe, mailslots основанны на все тех же Memory Mapped Files.
:D
Скажем так - спорное утверждение. Даже, весьма спорное. Например сразу возникает вопрос - а каким же образом мы можем при помощи этих механизмов (Name Pipe, mailslots) общаться внутри локальной сети?!
3. При чем тут OLE\ActiveX контейнеры я вообще не понял.
Человек имел ввиду механизм межпроцессорного взаимодействия СОМ, а именно маршалинг/демаршалинг, а точнее RPC.
При использовании WM_COPYDATA придется создать окно (ведь окна в приложении может и не быть), ставить в очередь сообщений и выбирать из нее это оконное сообщение, а работа с очередью сообщений весьма тормознутый процесс.
Это о-о-очень спорный вопрос. Ты ведь наверняка знаешь, что вся технология СОМ построена на передаче сообщений (см. Apartment'ы). Достаточно давно видел тесты от MS, там сравнивалась скорость работы обычной dll'ки и СОМ dll (in proc). И ты знаешь, компонент не сильно проигрывал в быстродействии (1 - 2% по моему, но могу врать не помню уже).
При этом система будет копировать информацию из одного адресного пространства в другое. Ну а уж о проблеме защиты и целостности информации я уж и не говорю.
Немного не так. Система создаёт Shared memory (Memory Mapped File), помещает туда информацию ( в source процессе) и передаёт указатель на адрес этой Shared памяти target процессу (см. Рихтера).
Так что вариант с WM_COPYDATA более накладен с точки зрения ресурсов (производительность, память). А уж надежность вообще никакая. Единственный плюс - простота реализации для новичков.
ХЗ.
Я написал всё это только потому - что мне кажется, что нельзя быть слишком категоричным. Последнее твоё утвержнение (насчёт надёжности и новичков) вообще не поддаётся критике.
Вопрос стоял так:
"...В одном процессе выделяем память, пишем в нее нужную информацию. Затем запускаем другой процесс и... SendMessage ..."
Отсюда следует:
1. Работа с Pipe вполне уместна (так как передача идет в порожденный процесс) - но все таки она не нужна, так как требует написания много кода, при этом я думаю, что это не будет в конечном итоге эффективно в моем случае.
2. Накладные расходы на обработку очереди сообщений ничтожно малы с самим запуском процесса, для которого они предназначались.
3. Наличие в моем вопросе слова "SendMessage" подразумевает, что в создаваемом процессе есть окно, которому я могу послать WM_COPYDATA
4. По поводу целостности и защиты информации - я так понимаю, это не моя забота, а забота операционной системы. И если она не смогла обеспечить эту целостность... Ну чтож тут можно поделать, она с таким же успехом могла бы и не обеспечить надежность работы других функций и в конечном итоге пользователь бы выбросил эту операционную систему.
Скажем так - спорное утверждение. Даже, весьма спорное. Например сразу возникает вопрос - а каким же образом мы можем при помощи этих механизмов (Name Pipe, mailslots) общаться внутри локальной сети?!
Видиться мне, что это проблема редиректора.
А подтверждение моих слов здесь:
http://www.codeproject.com/java/sharedmem_jni.asp
You can use window messages like WM_COPYDATA, pipe, sockets (just name a few) to share data between different processes on the same machine. But the most efficient way is to use memory mapped files. Because all the mechanisms mentioned above are using the memory mapped files internally, to do the dirty work.
Человек имел ввиду механизм межпроцессорного взаимодействия СОМ, а именно маршалинг/демаршалинг, а точнее RPC.
Я понял, что он имеет в виду. Но RPC однозначно медленнее, чем даже механизм оконных сообщений.
Это о-о-очень спорный вопрос. Ты ведь наверняка знаешь, что вся технология СОМ построена на передаче сообщений (см. Apartment'ы). Достаточно давно видел тесты от MS, там сравнивалась скорость работы обычной dll'ки и СОМ dll (in proc). И ты знаешь, компонент не сильно проигрывал в быстродействии (1 - 2% по моему, но могу врать не помню уже).
Ты хочешь сказать, что COM построен на передаче оконных сообщений?! Речь шла об оконных сообщениях.
Немного не так. Система создаёт Shared memory (Memory Mapped File), помещает туда информацию ( в source процессе) и передаёт указатель на адрес этой Shared памяти target процессу (см. Рихтера).
Спасибо. Я не был в этом до конца уверен, но в результате ты и статья с codeguru убедили меня окончательно. Так все же значит MMF. ;)
ХЗ.
Я написал всё это только потому - что мне кажется, что нельзя быть слишком категоричным. Последнее твоё утвержнение (насчёт надёжности и новичков) вообще не поддаётся критике.
Ну а мне кажется, что отстаивать свою точку зрения есть смысл только если в ней категорично уверен. На счет надежности остаюсь при своем мнении, механизм оконных сообщений менее надежен, чем MMF + SyncObj. Убедите меня в обратном. ;)
Ну а на счет новичков, это IMHO.
4. По поводу целостности и защиты информации - я так понимаю, это не моя забота, а забота операционной системы. И если она не смогла обеспечить эту целостность... Ну чтож тут можно поделать, она с таким же успехом могла бы и не обеспечить надежность работы других функций и в конечном итоге пользователь бы выбросил эту операционную систему.
Чаще пользователь выбрасывает не ОС, а такую программу.
Да, Windows неидеальная ОС, но в разработке ПО это надо учитывать и обходить её слабые места, а не кивать на разработчиков из MS.
Давай с самого начала.
Задача:
Переслать информацию (байтовый буфер размером ~100) через границу процесса.
Решения:
Мы анализируем 2 способа - MMF и SendMessage (..., WM_COPYDATA, ...).
Анализ решений:
MMF.
Создаём и инициализируем MMF в source процессе. Присваиваем имя объекту ядра MMF. Создаём механизм синхронизации для обеспечения последовательного доступа процессов к MMF (например именованные Event'ы). Пишем инфо в shared память в source процессе. Выставляем Event, что - бы сообщить target процессу о том, что можно читать инфо. В source процессе ждём на втором Event'е пока target процесс работает с разделяемой памятью.
Итог - для обеспечения этого механизма нам потребуется выделение 2 - х рабочих потоков по одному на source процесс и target процесс. Так же, потребуется создать механизм синхронизации для безопасного пользования разделяемой памяти (это могут быть не event'ы, может быть мьютекс и т.д.). Считаем память:
Для потока - (1мб стек, контекст потока ХХХ байт, регистры потока 256 * 4 байт) * 2 (у нас 2 потока). Для Event'ов - (не помню - сколько занимает памяти событие). Так же - необходимо создать механизм синхронизации между 2 - мя потоками (интерфейсным и рабочим) в каждом из процессов.
SendMessage (..., WM_COPYDATA, ...)
Просто берём и посылаем мессагу. ОС сама всё создаст за нас. Всё оптимизирует и гарантированно доставит инфо (когда - то был механизм DDE и MS заявляло - что он надёжен).
Резюме:
SendMessage использует меньше памяти, работает быстрее, проще кодить - а как следствие - меньше возможных багов.
IMHO естественно.
Ок.
Давай с самого начала.
Ну давай.
Задача:
Переслать информацию (байтовый буфер размером ~100) через границу процесса.
Решения:
Мы анализируем 2 способа - MMF и SendMessage (..., WM_COPYDATA, ...).
Ок, принимается.
Анализ решений:
MMF.
Создаём и инициализируем MMF в source процессе.
Присваиваем имя объекту ядра MMF. Создаём механизм синхронизации для обеспечения последовательного доступа процессов к MMF(например именованные Event'ы). Пишем инфо в shared память в source процессе. Выставляем Event, что - бы сообщить target процессу о том, что можно читать инфо. В source процессе ждём на втором Event'е пока target процесс работает с разделяемой памятью.
Итог - для обеспечения этого механизма нам потребуется выделение 2 - х рабочих потоков по одному на source процесс и target процесс. Так же, потребуется создать механизм синхронизации для безопасного пользования разделяемой памяти (это могут быть не event'ы, может быть мьютекс и т.д.). Считаем память:
Для потока - (1мб стек, контекст потока ХХХ байт, регистры потока 256 * 4 байт) * 2 (у нас 2 потока). Для Event'ов - (не помню - сколько занимает памяти событие). Так же - необходимо создать механизм синхронизации между 2 - мя потоками (интерфейсным и рабочим) в каждом из процессов.
Итоги не верны:
1) нет необходимости создания дополнительных потоков, справятся все теже "основные" потоки, их даже не надо заставлять ждать, можно просто проверять состояние объекта синхронизации;
2) для синхронизации последовательного доступа достаточно одного event-a;
3) Создание MMF - это вызов двух методов Win32 API (CreateFileMapping, MapViewOfFile), создание механизма синхронизации - в общей сложности еще два-три вызова.
4) все это можно однажды обернуть и использовать далее уже в более удобной форме, не хуже, чем SendMessage.
SendMessage (..., WM_COPYDATA, ...)
Просто берём и посылаем мессагу. ОС сама всё создаст за нас. Всё оптимизирует и гарантированно доставит инфо (когда - то был механизм DDE и MS заявляло - что он надёжен).
А где итоги и подсчеты? :)
Просто с наружи. Что же на самом деле:
1) в условии задачи нет упоминания, что окно существует, сл-но надо будет его создать даже если в нем нет необходимости;
2) source замирает до тех пор, пока сообщение не будет обработано в target. Т.о. вся работа source уже зависит от корректности работы target, заполненности очереди target, количества открытых окон в системе и т.д. К примеру в Outlook при перемещении указателя мыши с дерева на список приходит более 2000 сообщений, и даже не смотря на то, что это приложение не как не относится к нашемей задаче, оно будет влиять на нашу передачу данных. Разве не случалось у вас такое, когда все окна в системе замирают на некоторое время, пока не прочухается к примеру окно IE или Nero? Так вот такое замирание явно скажется на скорости передачи данных и производительности обоих приложений, особенно source. Количество окон в target, количество контролов в этих окнах, корректность обработчиков сообщений этих контролов и т.п., все это будет влиять на передачу информации и на производительность source;
3) в target придется снимать копию с переданных данных, т.к. надо как можно быстрее обработать сообщение и нельзя изменять данные наместе;
4) вместо однократного создания MMF (правда "вручную") он будет создаваться многократно (но "автоматом").
5) нет никаких гарантий, что информация будет доставлена. Сообщение может быть вытеснуто из очереди при оптимизации очереди, например, при приходе сообщения WM_CLOSE или WM_QUIT. Не стоит уповать на то, что раз окно закрывают (WM_CLOSE), то передаваемая информация уже не нужна. Не берусь утверждать про это сообщение (нет MSDN под рукой), но сообщение может быть отброшено при помощи механизма хуков оконных сообщений, не обязательно целенаправлено, а к примеру при некорректном использовании этого механизма.
Резюме:
SendMessage использует меньше памяти, работает быстрее, проще кодить - а как следствие - меньше возможных багов.
IMHO естественно.
Ну и с чего такие выводы?
Как SendMessage может использовать меньше памяти, если использует все тот же MMF? За счет неиспользования Event? А как-же память под структуру COPYDATASTRUCT, под копию буфера данных в target? :)
Как SendMessage может работать быстрее, если кроме все тех же действий с MMF, еще необходимо выполнить операции по определению потока в соотв. с HWND, постановки сообщения в очередь этого потока, выборку и обработку этого и всех предыдущих сообщений?
Я как-то придерживаюсь концепции Модель-Представление (Документ-Вид, если угодно), а при использовании WM_COPYDATA все мешается в кучу.
Не кажется ли вам, что каждый должен заниматься своим делом: механизм оконных сообщений работать для GUI, а передача информации между процессами с помощью механизма межпроцессного взаимодействия?
И уж чем меньше все это мешается в одну кучу, тем лучше.
Конечно, реализация на основе WM_COPYDATA для небольших программ с нечастой передачей коротких блоков информации выглядит проще, но это частный случай, а задача то стояла более абстрактно.
P.S. Я б, все равно, на месте автора вопроса использовал MMF... :D
Из личного опыта: удобнее это, корректнее и профессиональнее как-то.
Ну давай.
[skip]
Извини, что так и не ответил. Интересный разговор, только у меня времени сейчас совсем нет. Я сейчас работу сменил, и работаю на испытательном сроке.
P.S. Давай лучше на ты общаться. :) Когда в Лоцмане пиво пили, тогда и познакомились. Помнишь? :D