Форум: "WinAPI";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];
ВнизСинхронизация двух процессов Найти похожие ветки
← →
DeadMeat © (2005-09-26 11:41) [0]Доброго времени суток, уважаемые.
Вот такая у меня проблемка появилась.
Есть два процесса. Один процесс запускает другой. В каждом их них стоит проверка на существование друг-друга (WaitForSingleObject). В первом она стоит в основном потоке, а во втором - это отдельный поток.
Первый процесс мой - второй соответственно не мой.
Если в первом все ок, то во втором уже дурдом.
Мне нужно сделать так, чтобы при завершении одного из них, завершался и другой. Учитывая что второй процесс не моих рук дело, я решил использовать внедрение. Но до этого дело не дошло.
Для начала решил проверить в чистом проекте сам способ.
Так вот. Для проверки запускаю "блокнот" и "синхронизирую" свой процесс с ним, т.е. когда блокнот закроют мне надо закрыть себя.
Идея следующая:
- получитьhandle
целевого процесса (за которым надо следить) используяOpenProcess
;
- запустить на выполнение поток, передав ему этотhandle
;
- в потоке уже использоватьWaitForSingleObject
;
- после нее, уже ExitProcess (0).
Начал реализовывать:
.....
var thid:cardinal;
.....
function watcher (param:pointer):integer;
var bufhnd:THandle;
begin
bufhnd:=THandle (param^);
MessageBox (0,pchar (inttostr (bufhnd)),"Handle",mb_ok);
end;
.....
var bufhnd:THandle;
begin
bufhnd:=OpenProcess (SYNCHRONIZE,false,4064); //здесь PID я вручную поставил, чтобы не возиться с поиском.. знаю.. плохо.. но лень.. зато 100% он правильный.
MessageBox (0,pchar (SysErrorMessage(GetLastError)),"Result",mb_ok);
caption:=inttostr (bufhnd);
beginthread (nil,0,watcher,@bufhnd,0,thid);
end;
Правильно ли я все сделал?
Так или иначе вот в чем проблема:
- при запуске потока, значение получается совсем другое.. вообще "левое";
- при пошаговом выполнении, все прекрасно работает, т.е. значение получается нужное;
- если этот же кусок кода вставит в DLL, которая внедряется во "второй" процесс (естественно безcaption
.. тут это просто для отладки.. так проще...), тоGetLastError
уже говорит чтото типа"Параметр задан не верно"
, а в чистом проекте все ок;
- если в DLL, в этом куске убратьbeginthread
, тоGetLastError
уже возвращает"Операция прошла успешно"
.
Не могли бы Вы меня, уважаемые мастера, "ткнуть" носом туда, где я ошибся...??
Заранее благодарен за любую информацию.
← →
Digitman © (2005-09-26 12:15) [1]начнем с того, что процессы не могут ждать друг-друга, чтобы "одновременно завершиться" - сие есть классическая ситуация "мертвой блокировки" (deadlock)
← →
GuAV © (2005-09-26 13:05) [2]
> - при запуске потока, значение получается совсем
> другое.. вообще "левое";
Ты наверное передаёшь указатель на локальную преременную в BeginThread. Когда дело доходит до потока, она уже не существует. Передавай:
1. Саму переменную
2. Дин. выделенную переменную, в чатности запись или класс, который освобождай из watcher.
3. Ничего не передавай, используй глобальную переменную.
← →
GuAV © (2005-09-26 13:09) [3]
> - после нее, уже ExitProcess (0).
Плохо. IMHO, Halt(0) лучше. При этом нужно проследить, чтобы основной поток не вызвал Halt.
Наилучшим вариантом будет ожидание в основном потоке. Если там требуется обрабатывать сообщения, можно ожидать через MsgWaitчегототам.
← →
ANB © (2005-09-26 14:01) [4]
> Есть два процесса. Один процесс запускает другой. В каждом
> их них стоит проверка на существование друг-друга (WaitForSingleObject).
> В первом она стоит в основном потоке, а во втором - это
> отдельный поток.
1) если модуль второго процесса написан не тобой, то как ты этого добьешься ?
2) Какой у этого логический смысл ?
3) Для синхронизации в одну сторону делается все просто :
а) из своего приложения запускашь управляемый процесс (CreateProcess). Далее в этом же своем потоке ждешь, пока он не завершиться, любым способом, например :
// Найдем хэндл текущего процесса
hProcess := OpenProcess (SYNCHRONIZE, False, dwProcessID);
try
// Если ошибка - процесс уже закончился и можно выходить.
if (hProcess = 0) then Exit;
tmStart := Now;
while (TimeIntervalToMiliSec(Now - tmStart) <= tmWait) do begin
if (fmLog.bStop) then Exit; // Это моя обработка нажатия кнопки стоп, можешь запихать всюда все, что нужно. Не забудь Application.ProcessMessages;
dwRW := WaitForSingleObject(hProcess, 100);
if ((dwRW = WAIT_ABANDONED) or (dwRW = WAIT_OBJECT_0)) then begin
Exit;
end;
end;
finally
CloseHandle(hProcess);
end;
4) При работе с внедренной DLL нужно учитывать, что все глобальные/локальные ее переменные в другом процессе очищаются и нужно заново их инициализировать. Чтобы передать какие то данные, их нужно передавать через MMF или сообщения.
← →
DeadMeat © (2005-09-26 14:38) [5]
> Digitman © (26.09.05 12:15) [1]
Честно сказать не совсем понял, что вы имели ввиду. Мне всего то надо, закрыть одну программу, когда другую закроют. И более ничего.
> GuAV © (26.09.05 13:05) [2]
Вот, блин, об этом я совсем не подумал. Упустил из виду. Видимо погаговая трассировка, при которой все работает, сбила меня с толку... Спасибо.
> GuAV © (26.09.05 13:09) [3]
Учту.. Спасибо еще раз.
> ANB © (26.09.05 14:01) [4]
> 1) если модуль второго процесса написан не тобой, то как
> ты этого добьешься ?
Внедрив DLL, в которой будет проверка на "существование" первого процесса.
> 2) Какой у этого логический смысл ?
Такова задача. Закрыть второе приложение, когда закрывается первое и наоборот. Просто первое является загрузчиком второго.
> 3) Для синхронизации в одну сторону делается все просто
> :
> а) из своего приложения запускашь управляемый процесс (CreateProcess
).
> Далее в этом же своем потоке ждешь, пока он не завершиться,
> любым способом, например :
Примерно так у меня все и реализовано. С этим проблем нет, но все равно спасибо. Только еще проще: запуск черезCreateProcess
и ожидание черезWaitForSingleObject
. После этого просто выход из основного потока. Паралельно ведется своя работа в дополнительном потоке.
> 4) При работе с внедренной DLL нужно учитывать, что все
> глобальные/локальные ее переменные в другом процессе очищаются
> и нужно заново их инициализировать. Чтобы передать какие
> то данные, их нужно передавать через MMF или сообщения.
Спасибо за замечание. Нечто похожее уже реализовано и с этим тоже проблем пока не наблюдается.
Спасибо еще раз всем за ответы.
Чуть позже смогу проверить и "доложить".
← →
GuAV © (2005-09-26 15:01) [6]
>> Digitman © (26.09.05 12:15) [1]
>
> Честно сказать не совсем понял, что вы имели ввиду.
Имелось ввиду, что если один поток 1 не сигнализирует объект А, пока не будет сигнализирован объект Б, а поток 2 не сигнализирует объект Б, пока не будет сигнализирован объект А, наступает взаимоная блокировка этих потоков, "тупик" или "deadlock".
К твоему случаю было бы применимо если бы таждый из процессов завершался бы тогда, и ТОЛЬКО тогда, когда завершается другой.
← →
DeadMeat © (2005-09-26 15:25) [7]
> GuAV © (26.09.05 15:01) [6]
Теперь понятно. Спасибо за разьяснения.
У меня действительно случай несколько иной. Каждый из процессов может быть завершен принудительно пользователем.
По сабжу... Все работает. Перенес переменную в глобальную.
Спасибо всем, вопрос исчерпан. Далее буду допирать сам.. в чем было дело.
← →
GuAV © (2005-09-26 15:36) [8]Ещё замечание... чужой процесс IMHO лучше всего завершать через WM_SYSCOMMAND - SC_CLOSE его окну, чтобы он мог выполнить действия по завершению, и "убивать" через ExitProcess уже по таймауту.
← →
Leonid Troyanovsky © (2005-09-26 16:13) [9]
> GuAV © (26.09.05 15:36) [8]
> действия по завершению, и "убивать" через ExitProcess уже
> по таймауту.
Тут либо TerminateProcess по таймауту (снаружи),
либо уж дать WM_SYSCOMMAND - SC_CLOSE отработать до конца
(куда уж тут совать таймаут).
--
Regards, LVT.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.015 c