Среда MSVC++ c MFC
Вопрос такой, есть основное приложение, оно запускает дополнительные потоки (в терминах MSDN userinterface thread, потоки наследуются от CWinThread) соответственно в каждом потоке свое окно.
Если закрываем дочерние окна — все нормально.
Если закрываем основное окно, то доп потоки убиваются уже без моего участия (что сильно расстраивает) причем убиваются они как то жестко, потому что даже WM_QUIT они не получают.
Проблема решается, отслеживанием того, чего насоздавали и рассылкой в CWinApp::ExitInstance() всем потокам WM_QUIT.
Однако, если теперь функциональность, связанную с доп потоками, вынести в ДЛЛ, то отслеживать и убивать их из основного приложения, становится совсем не хорошо — т.е. просто такой вариант нельзя делать в силу ограничений накладываемых на задачу. Соответствено, потоки убиваются не правильно — я бы не сильно переживал на этот счет, не настолько я пунктуальный программист, но работа потоков подразумевает создание временного файла который надо убивать по завершению потока(на самом деле все несколько сложнее, однако, суть дела не меняется), и то что это не происходит сильно напрягает.
Попытка отлова всевозможных DLL_THREAD_DETACH,DLL_PROCESS_DEATTACH,... в DllMain успехом не увенчались(вполне вероятно, что я просто не то в них делал) , но
DLL_THREAD_DETACH — ни разу не пришло
DLL_PROCESS_DEATTACH — приходит стабильно, но к этому времени мои доп потоки настолько занасилованы системой, что смысл их убивать уже нет, они и так не живые.
_________
Вот здесь исходники тестового приложения(~8КБ) тока ногами не пинать, я на С++ с MFC пишу всего полгода
Здравствуйте, Аноним, Вы писали:
А>Среда MSVC++ c MFC А>Вопрос такой, есть основное приложение, оно запускает дополнительные потоки (в терминах MSDN userinterface thread, потоки наследуются от CWinThread) соответственно в каждом потоке свое окно. А>Если закрываем дочерние окна — все нормально. А>Если закрываем основное окно, то доп потоки убиваются уже без моего участия (что сильно расстраивает) причем убиваются они как то жестко, потому что даже WM_QUIT они не получают.
А>Проблема решается, отслеживанием того, чего насоздавали и рассылкой в CWinApp::ExitInstance() всем потокам WM_QUIT.
А>Однако, если теперь функциональность, связанную с доп потоками, вынести в ДЛЛ, то отслеживать и убивать их из основного приложения, становится совсем не хорошо — т.е. просто такой вариант нельзя делать в силу ограничений накладываемых на задачу. Соответствено, потоки убиваются не правильно — я бы не сильно переживал на этот счет, не настолько я пунктуальный программист, но работа потоков подразумевает создание временного файла который надо убивать по завершению потока(на самом деле все несколько сложнее, однако, суть дела не меняется), и то что это не происходит сильно напрягает.
А>Попытка отлова всевозможных DLL_THREAD_DETACH,DLL_PROCESS_DEATTACH,... в DllMain успехом не увенчались(вполне вероятно, что я просто не то в них делал) , но А>DLL_THREAD_DETACH — ни разу не пришло А>DLL_PROCESS_DEATTACH — приходит стабильно, но к этому времени мои доп потоки настолько занасилованы системой, что смысл их убивать уже нет, они и так не живые. А>_________
А>Вот здесь исходники тестового приложения(~8КБ) тока ногами не пинать, я на С++ с MFC пишу всего полгода
Вполне реальный выход — вставить в dll функцию (экспортируемую) типа CloseChildWindows с требованием клиенту вызывать ее перед завершением основного приложения. dll тоже модуль и имеет право на свой обработчик завершения.
Re[2]: Потоки в ДЛЛ, когда надо их прибивать?
От:
Аноним
Дата:
21.03.03 14:13
Оценка:
KB>Вполне реальный выход — вставить в dll функцию (экспортируемую) типа CloseChildWindows с требованием клиенту вызывать ее перед завершением основного приложения. dll тоже модуль и имеет право на свой обработчик завершения.
Низя так, первое что я предложил это при создании потока в ДЛЛ посылать сообщение основному процессу, при умирании потока своей смертью тоже, а в CGeneralWinApp::ExitInstance() — давить не до давленных.
Но основное приложение на предмет доп фнкциональности дадут по трогать только при строгом док-ве, что по другому никак.... вот и мучаюсь
Здравствуйте, Аноним, Вы писали:
KB>>Вполне реальный выход — вставить в dll функцию (экспортируемую) типа CloseChildWindows с требованием клиенту вызывать ее перед завершением основного приложения. dll тоже модуль и имеет право на свой обработчик завершения.
А>Низя так, первое что я предложил это при создании потока в ДЛЛ посылать сообщение основному процессу, при умирании потока своей смертью тоже, а в CGeneralWinApp::ExitInstance() — давить не до давленных. А>Но основное приложение на предмет доп фнкциональности дадут по трогать только при строгом док-ве, что по другому никак.... вот и мучаюсь
А дочерним окнам не приходит чего-нибудь тривиального типа WM_CLOSE?
Re[4]: Потоки в ДЛЛ, когда надо их прибивать?
От:
Аноним
Дата:
21.03.03 18:27
Оценка:
KB>А дочерним окнам не приходит чего-нибудь тривиального типа WM_CLOSE?
вся неприятность положения заключается в том, что окна создаваемые доп потоками они по первоначалу на длительный период времени заняты — там список заполняется здоровый (для чего в отдельный поток и вынесены), соответственно они вообще сообщения не обрабатывают, но при этом закрытие основного окна гасит потоки по любому и сразу, вне зависимости от того заполняется этот список или уже заполнен. соответственно WM_CLOSE не приходит, я то хотел найти момент когда доп окна гасят и поставить там какой-нибудь event, чтобы выскочить из процедуры заполнения списка, и нормально закончится, а момент этот все-таки, наверное, можно поймать только в ExitInstance основного приложения, потом уже поздно пить баржоми, система сама разбирается с моими потоками ....
Просто надеялся, что ошибюсь и можно как то измудриться и реализовать все внутри ДЛЛ, наверное, не выйдет
Здравствуйте, <Аноним>, Вы писали:
А>Просто надеялся, что ошибюсь и можно как то измудриться и реализовать все внутри ДЛЛ, наверное, не выйдет
Нет, ну измудриться как раз таки можно — покрупному.
Поставить во всех dll'ках WH_GETMESSAGE хук (::SetWindowsHookEx) для основнового треда (из dll'ки можно поставить и общесистемный, но так, конечно, лучше не поступать). И в обработчике отлавливать WM_QUIT, запощщеный в главный тред. Хук будет вызван в контексте главного треда — в каждом из них ждите завершения соответствующего (этому хуку) треда.
А если продолжить измудряться, то можно поиметь и один хук на всех — диспетчер, который будет корректно ожидать завершения всех зарегистрированых у него тредов.
Но скажу мое мнение — измудрение это полнейшее. В случает множества хуков, может упасть производительность главного треда (ведь тысячи глаз будут следить за _каждым_ посылаемым ему сообщением), во втором это жестокое усложнение архитектуры dll'лок.
P.S.
Когда уже дописывал, вспомнил, что тут топик проплывал флеймовый о возможной засаде при обработке именно WM_QUIT (ведь его постят через PostQuitMessage, а не как все остальные через PostMessage), что-то там со внутренними флагами, которые устанавливает PostQuitMessage, но по-моему это не относиться к этому делу, но вам стоит с ним ознакомиться (в гораздо большей степени, чем это сделал я(:. Топик SendMessage vs. PostMessage
, в особенности пост тов. Valerio, оцененный в 13 балов.
Re[6]: Потоки в ДЛЛ, когда надо их прибивать?
От:
Аноним
Дата:
22.03.03 04:42
Оценка:
А>>Просто надеялся, что ошибюсь и можно как то измудриться и реализовать все внутри ДЛЛ, наверное, не выйдет
F>Нет, ну измудриться как раз таки можно — покрупному.
F>Поставить во всех dll'ках WH_GETMESSAGE хук (::SetWindowsHookEx) для основнового треда (из dll'ки можно поставить и общесистемный, но так, конечно, лучше не поступать). И в обработчике отлавливать WM_QUIT, запощщеный в главный тред. Хук будет вызван в контексте главного треда — в каждом из них ждите завершения соответствующего (этому хуку) треда.
Спасибо, по крайней мере хоть какое-то решение, надеюсь правда до такого дело не дойдет, и все таки уговоримся чуть подкорректировать основное приложение, добавив убиение дочерних тредов.
F>Но скажу мое мнение — измудрение это полнейшее. В случает множества хуков, может упасть производительность главного треда (ведь тысячи глаз будут следить за _каждым_ посылаемым ему сообщением), во втором это жестокое усложнение архитектуры dll'лок.
с этим я согласен, я просто не могу, в силу своей слабой компетентности, однозначно ответить "внутри длл это можно сделать только вот так, так делать плохо, давайте переделаем главное приложение"
Здравствуйте, Аноним, Вы писали:
А> работа потоков подразумевает создание временного файла который надо убивать по завершению потока(на самом деле все несколько сложнее, однако, суть дела не меняется), и то что это не происходит сильно напрягает.
может просто завести в DLL статическую глобальную переменную(класс) и в ее деструкторе поубивать всех нафиг и позакрывать все файлы ? Че-то типа:
// где-то в DLL
FILE* files[N];
HANDLE threads[N];
struct CloseAllFiles
{
~CloseAllFiles()
{
for (i = 0; i < N; ++i)
TerminateThread(thread[i]);
for (i = 0; i < N; ++i)
if (file[i])
fclose(i);
}
}
} Terminator;
Re[2]: Потоки в ДЛЛ, когда надо их прибивать?
От:
Аноним
Дата:
22.03.03 16:33
Оценка:
bnk>может просто завести в DLL статическую глобальную переменную(класс) и в ее деструкторе поубивать всех нафиг и позакрывать все файлы ? Че-то типа:
убивать уже поздно ... просто замочить лишние файлы как Вы сами понимаете не основная проблема.... в конце концов их то можно мочить и в DllMain на DLL_PROCESS_DEATTACH, просто хотелось все сделать по правильному, чтобы раз я завел потоки я их и убив.
Здравствуйте, Аноним, Вы писали:
KB>>А дочерним окнам не приходит чего-нибудь тривиального типа WM_CLOSE?
А>вся неприятность положения заключается в том, что окна создаваемые доп потоками они по первоначалу на длительный период времени заняты — там список заполняется здоровый (для чего в отдельный поток и вынесены), соответственно они вообще сообщения не обрабатывают,
Смотрим дизайн MFC — один поток (главный, UI) крутит message loop и создает все оконные объекты, рабочие потоки поставляют данные визуальным контролам, о чем докладывают механизмами синхронизации. Здесь нужно сделать то же самое.
А>но при этом закрытие основного окна гасит потоки по любому и сразу, вне зависимости от того заполняется этот список или уже заполнен. соответственно WM_CLOSE не приходит,
Хэндлы потоков, похоже, закрываются, из чего система делает справедливый вывод, что их (потоки) смело можно грохнуть, ибо воспользоваться данными из них уже не представляется возможным.
А>я то хотел найти момент когда доп окна гасят и поставить там какой-нибудь event,
Потоки должны тогда регулярно проверяться на предмет этого event'а (речь именно о событии, а не посылке оконного сообщения).
А> чтобы выскочить из процедуры заполнения списка, и нормально закончится, а момент этот все-таки, наверное, можно поймать только в ExitInstance основного приложения, потом уже поздно пить баржоми, система сама разбирается с моими потоками .... А>Просто надеялся, что ошибюсь и можно как то измудриться и реализовать все внутри ДЛЛ, наверное, не выйдет
Здравствуйте, Игорь Вартанов, Вы писали:
А>>Просто надеялся, что ошибюсь и можно как то измудриться и реализовать все внутри ДЛЛ, наверное, не выйдет
ИВ>Ошибаешься. Можно. Внутри. Выйдет.
я наверное очень тупой, но какэто сделать их вашего поста не понял, какое событие и где надо ожидать?
Далее всем порождаемым потокам передается его хэндл, на котором они (потоки) периодически должны делать WaitForSingleObject() с нулевым таймаутом. Если объект в несигнальном состоянии ("можно работать"), то она вернет WAIT_TIMEOUT, если же в потоке главного окна произошло "нечто" (SetEvent(hStopEvent)), в результате чего событие установлено в сигнальное состояние, то Wait-функция вернет WAIT_OBJECT_0, что значит "событие установлено, бросай все, щас будут убивать".
Если мирное завершение потоков занимает значительное время, тот необходимо наладить обратную связь — главное окно умрет лишь после того, как все потоки доложат о завершении (либо после защитного таймаута разумной продолжительности, если возможны зависы в потоках).
Итак, имеем все окна в главном потоке, крутящем цикл сообщений, и, следовательно, всегда реагирующий юзер-интерфейс, и рабочие потоки, поставляющие данные дочерним окнам и мониторящие на протяжении всей своей жизни стоп-событие.
Если все кажется сложным, то рекомендую написать приложение-болванку, на которой обкатать основную схему взаимодействия окон, потоков и событий. После все будет казаться ясным и логичным.
Основное условие задачи "нельзя менять основное приложение" если бы было можно, вопросов бы не было,
ИВ>Главное окно создается, и при этом создается объект ядра "event" в несигнальном состоянии.
главное окно создается в основном приложении. выставлять там event я не могу.
ИВ> ИВ>Далее всем порождаемым потокам передается его хэндл, на котором они (потоки) периодически должны делать WaitForSingleObject() с нулевым таймаутом. Если объект в несигнальном состоянии ("можно работать"), то она вернет WAIT_TIMEOUT, если же в потоке главного окна произошло "нечто" (SetEvent(hStopEvent)), в результате чего событие установлено в сигнальное состояние, то Wait-функция вернет WAIT_OBJECT_0, что значит "событие установлено, бросай все, щас будут убивать".
ИВ>Если мирное завершение потоков занимает значительное время, тот необходимо наладить обратную связь — главное окно умрет лишь после того, как все потоки доложат о завершении (либо после защитного таймаута разумной продолжительности, если возможны зависы в потоках).
Здравствуйте, Alglib, Вы писали:
A>ну не могу я главное приложение менять.
Ладно, не можешь — не надо. Но развести оконный и рабочий потоки для каждого окна ты можешь? Окно будет "живым" и сможет получить WM_CLOSE и посредством события (да-да, в этой ситуации у каждого окна будет два потока и событие для возможной остановки рабочего потока) стопить поток данных.
Кстати, это будет весомым аргументом для умников, не желающих менять основное приложение — "хотите — будет вам куча потоков и объектов ядра".
Здравствуйте, Игорь Вартанов, Вы писали: A>>ну не могу я главное приложение менять.
ИВ>Ладно, не можешь — не надо. Но развести оконный и рабочий потоки для каждого окна ты можешь? Окно будет "живым" и сможет получить WM_CLOSE и посредством события (да-да, в этой ситуации у каждого окна будет два потока и событие для возможной остановки рабочего потока) стопить поток данных.
что значит развести оконный и рабочий поток? и почему при этом WM_CLOSE будет приходить если сейчас в доп окна оно по закрытию основного не приходит? (вы меня извините за столь глупые вопросы — но не понимаю)
Вариант, когда доп окна работают в том же потоке, что основное, а вот данные в них запихиваются тн рабочим потоком, рассматривался — сложно получается, не так чтобы "ОЧЕНЬ СЛОЖНО" но не хотелось бы, через это по сути и начал пользовать юзверь интерфейс поток.
ИВ>Кстати, это будет весомым аргументом для умников, не желающих менять основное приложение — "хотите — будет вам куча потоков и объектов ядра".
нет тут вопрос не в том что они уперлись рогом, люди вполне вменяемы, просто менять основное приложение, на основании просто моего пожелания — глупо, у меня нет достаточной квалификации, надо весомое подтверждение которым в том числе явилось отсутствие предложений на двух конференциях