Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.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
Цитата yasli @
Заниматься переопределением, думаю, нецелесообразно.

Целесообразно и правильно. Все методы у CListCtrl всего лишь обёртки над SendMessage, посмотри их реализацию. Их нельзя вызывать в другом потоке.


Цитата yasli @
Оставил проверку на флаг завершения потока перед обращением к контролам. Спасибо!

Это не поможет. Дедлок будет возникать реже, но регулярно. Всегда пожалуйста.

Автор: yasli 17.06.17, 17:51
Цитата Олег М @
Цитата yasli @
Заниматься переопределением, думаю, нецелесообразно.

Целесообразно и правильно. Все методы у CListCtrl всего лишь обёртки над SendMessage, посмотри их реализацию.

А как/где посмотреть их реализацию?

Автор: Олег М 18.06.17, 05:44
Цитата yasli @
А как/где посмотреть их реализацию?

В исходниках. Например 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
Цитата Олег М @
Цитата yasli @
А как/где посмотреть их реализацию?

В исходниках. Например 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
Большое всем спасибо!

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)