Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > Visual C++ / MFC / WTL > В какой момент уничтожаются члены класса диалога? |
Автор: yasli 16.06.17, 08:42 |
В диалоговом приложении запускается поток (AfxBeginThread), который в цикле опрашивает web-сервис и выводит на форму некоторую информацию. При закрытии основной формы в событии OnClose устанавливаю флаг завершения потока (он в цикле потоковой функции проверяется) и жду завершения потока (WaitForSingleObject), а функция потока в этот момент еще парсит длинный ответ сервера и пытается вывести информацию в контрол на форме. На строчке обращения к переменной-члену, связанному с контролом всё зависает. Перед обращением к этой переменной, конечно, можно проверять установлен или нет флаг завершения потока, но всё-таки интересно, почему всё зависает, ведь в событии OnClose (когда получено сообщение WM_CLOSE), все члены класса диалога еще существуют. Как сделать правильно? |
Автор: Олег М 16.06.17, 08:50 |
Зависает, скорее всего потому, что у тебя поток посылает сообщение, синхронное, контролу (при помощи SendMessage), однако в это время обрабатывается тоже синхронное сообщение WM_CLOSE, которое ждёт завершения потока. В результате - дедлок. В потоке нужно посылать сообщение при помощи PostMessage. |
Автор: yasli 16.06.17, 10:50 |
Ну, я использую стандартные контролы и их стандартные методы, CListCtrl, в частности... Заниматься переопределением, думаю, нецелесообразно. Оставил проверку на флаг завершения потока перед обращением к контролам. Спасибо! |
Автор: Олег М 16.06.17, 13:19 |
Целесообразно и правильно. Все методы у CListCtrl всего лишь обёртки над SendMessage, посмотри их реализацию. Их нельзя вызывать в другом потоке. Это не поможет. Дедлок будет возникать реже, но регулярно. Всегда пожалуйста. |
Автор: yasli 17.06.17, 17:51 |
Цитата Олег М @ Целесообразно и правильно. Все методы у CListCtrl всего лишь обёртки над SendMessage, посмотри их реализацию. А как/где посмотреть их реализацию? |
Автор: Олег М 18.06.17, 05:44 |
В исходниках. Например D:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\include\afxcmn.inl |
Автор: yasli 19.06.17, 20:16 |
А может быть такое, что какое-нибудь сообщение, отправленное с пом. PostMessage придёт уже после того, как окно, которому оно отправлено, будет уничтожено? Могут ли возникать утечки памяти в этом случае? И как их избежать, если могут? |
Автор: ЫукпШ 19.06.17, 20:55 |
Цитата yasli @ ..и жду завершения потока (WaitForSingleObject), а функция потока в этот момент еще парсит длинный ответ сервера и пытается вывести информацию в контрол на форме. А пусть она (функция потока) делает это не так. Не надо выводить информацию на контрол из потока. Пусть поточная функция пошлёт информацию оконной процедуре посредством "PostMessage" заранее обусловленным сообщением. А уже оконная процедура раздаёт информацию контролам. --- Если в какой-то момент окно получит WM_CLOSE, обработчик этого сообщения может просто логически "отключить" функционал обработчика сообщений с данными. И никаких "коллизий" не будет. Например, попытки работать с уже уничтоженными контролами. При такой логике работы можно будет заменить работу с WM_CLOSE работой с WM_DESTROY. |
Автор: Олег М 20.06.17, 04:35 |
Цитата yasli @ А может быть такое, что какое-нибудь сообщение, отправленное с пом. PostMessage придёт уже после того, как окно, которому оно отправлено, будет уничтожено? Могут ли возникать утечки памяти в этом случае? И как их избежать, если могут? Без разницы. Сообщение просто не обработается и всё, никаких утечек не будет. Проблемы могут возникнуть по другой причине - там в большинство сообщении нужно отправлять адреса структур. Т.к. сообщение посылается асинхронно, через PostMessage, нужно как-то гарантировать, что эти структуры будут ещё живы на момент обработки. Цитата ЫукпШ @ Не надо выводить информацию на контрол из потока. Пусть поточная функция пошлёт информацию оконной процедуре посредством "PostMessage" заранее обусловленным сообщением. А уже оконная процедура раздаёт информацию контролам. Да, примерно так. Сохраняешь данные в какой-нибудь переменной класса, После изменения их в потоке делаешь PostMessage(WM_USER......) В обработчике этого WM_USER.... вызываешь нужные методы CListCtrl. Либо можно, наверное, использовать SendMessageTimeout для отправки сообщений из потока |
Автор: ЫукпШ 20.06.17, 09:04 |
Цитата Олег М @ Проблемы могут возникнуть по другой причине - там в большинство сообщении нужно отправлять адреса структур. Т.к. сообщение посылается асинхронно, через PostMessage, нужно как-то гарантировать, что эти структуры будут ещё живы на момент обработки. Очень просто. Между потоком и оконной процедурой организуем потоко-безопасную очередь. Например, указателей на структуры данных. Если структуры невелики по размеру, можно очередь структур. Поток выделяет память для структуры. Заносит данные в структуру, указатель размещает в очередь, посылает уведомление оконной процедуре (WM_APP + xx). В самом сообщении можно вообще не пересылать никаких данных. Или пересылать какой-либо признак, характеризующий данные, если вариантов данных много. Но это по-вкусу. После этого поток забывает об обработанных уже данных и готов к получению новых. Оконная процедура в обработчике сообщений проверяет наличие данных в очереди, извлекает их, если имеются, преобразует/раздаёт, ликвидирует структуру. |
Автор: yasli 21.06.17, 10:07 |
Цитата Олег М @ В исходниках. Например D:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\include\afxcmn.inl Там, похоже, не все функции содержатся. Не нашел CListCtrl::GetItemText и CListCtrl::SetItemText. Где они еще могут быть?.. |
Автор: Cfon 21.06.17, 10:41 |
Цитата yasli @ см в winctrl2.cpp |
Автор: yasli 21.06.17, 18:55 |
Большое всем спасибо! |