Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Как отрисовать объекты из дополнительного потока?


Автор: takedo 1.6.2005, 11:51
Люди!!!
Вот какая приключилась проблема:
Программа должна получать данные из com порта и в соответствии со значениями перерисовывать объекты на CScrollView SDI приложения. Объекты - производные от CButton со стилем BS_OWNERDRAW. Объекты имеют встроенные функции типа SetState(){.... Invslidate();}. В программе много чего ещй есть, но не по суте, поэтому опущено. До тех пор, пока не был создан дополнительный поток, в котором в цикле пробегаем по всем объектам и по Random генерируем данные с вызовом SetState, все работало замечательно. Как только перерисовка стала делаться из потока - появились непонятные Exception. Дело наверное в синхронизации. Так вот вопрос - как это организовать, что надо защищать от совместного доступа и возможно ли это осуществить с применением "рабочего" потока???
Помогите пожалуйста... smile

Автор: Coocky 1.6.2005, 13:15
takedo
вО ПЕРВЫ . хотелось бы узнать, что Exception выдает.
2.
Цитата
В программе много чего ещй есть, но не по суте, поэтому опущено

А вот это зря, интересно было б узнать, ЧТО творится в потоках...

Автор: takedo 1.6.2005, 15:08
Собственно программа должна собрать информацию об объектах. Объекты имеют четыре параметра и несколько состояний: активен, неактивен и др. Программа построена на базе SDI. как уже говорилось, объекты произведены от CButton и объеденены на CFrameWnd, являющемся их родителями. В их же родителе вызывается и обработчик события BN_CLICKED для них. При обработке вызывается настройка - произведена от CPropertySheet c двумя вкладками - для просмотра и настройки. В настройке мы должны задавать значения параметров и отсылать их устройству-объекту.
Программа должна фоном генерировать запросы через Com порт объектам и получать ответы, изменяя отображение их на экране(то есть перерисовывать в DrawItem кнопки). Если изменилась информация об объекте в момент, когда у него вызвано окно настроек - окно настроек тоже надо перерисовать. Помимо фоновых команд должно быть предусмотрен механизм отсылки команд не в фоне, а по нажатию соответствующей кнопки в окне настроек(при изменении параметров). Но скорее всего надо сперва послать команду на изменение, а затем изменить отображение после получения уже фоновой команды.
Так вот, все было хорошо, пока не начал подготавливаться к передаче данных. Создал поток и решил просто пробежаться по всем объектам меняя их состояние(т.е цвет). При завершении программы получается, но не всегда
"Unhandled exception at 0x7c34c97a (mfc71ud.dll) in jp.exe: 0xC0000005: Access violation reading location 0x00000020.".
Как быть - просто не знаю. Буду очень благодарен, если с чьей - либо помощью удасться решить эту проблему.

Автор: Coocky 1.6.2005, 15:10
takedo
Цитата
Unhandled exception at 0x7c34c97a (mfc71ud.dll) in jp.exe: 0xC0000005: Access violation reading location 0x00000020

Через отладчик можешь глянуть, в каком месте вылетает?
Добавлено @ 15:15
Вообще скажу одно-если обращаешься из разных потоков к одному обьекту, тогда нужна синхронизация

Автор: takedo 1.6.2005, 15:18
вылетает в функции UpdateMy окна настроек, при строках типа
CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT_V1); и т.д, в которой и происходит изменение отображения. Также в ней позже вызывается и InvalidateRect но до него и не доходит. Когда это окно закрыто - UpdateMy не вызывается а отображаются только кнопки, нажимая на мышку и сворачивая несколько раз фрейм можно добиться того-же самого.

Автор: Coocky 1.6.2005, 15:24
takedo
Цитата
CEdit* edit = (CEdit*)GetDlgItem(IDC_EDIT_V1);

Что внизу пишет(watch)- edit=??????
Или что другое, там где остановится, внизу смотри, какя ошибка.

Автор: takedo 1.6.2005, 15:27
в том то и дело - не знаю даже какой это объект - может быть CDC???
Хотя только вот вот попробовал посылать ::SendMessage(hwnd,WM_MYMESSAGETOREDRAW,0,0); из потока в кнопку и тоже ничего не дало - все также. я готов и поэкспериментировать в CDialog с одной двумя моими кнопками, лишь бы точно знать как и что делать!!!

Автор: Coocky 1.6.2005, 15:28
takedo
Цитата
в том то и дело - не знаю даже какой это объект - может быть CDC

да посмотри при отладке внизу в окне, быть такого не может, что б ошибку не показало..

Автор: takedo 1.6.2005, 15:32
бывает и Debug Assertion Failed!
File: winprocc.cpp и ничего не посмотришь! Но! сначала убивается добавочный поток, потом основной, а в процессе работы(до закрытия) все нормально в edit. Я и говорю, что все было в порядке, до тех пор как не начал из потока отрисовывать.
Да я вообще хотел бы просто узнать как такие вещи делают? начал бы заново, если бы знать как! Подскажите, пожалуйстаааа.
Добавлено @ 15:33
когда ненормально завершается, тогда и такое бывает
Detected memory leaks!
Dumping objects ->
{10733} normal block at 0x0032F658, 70 bytes long.
Data: < C| > B8 AE 43 7C 1A 00 00 00 1A 00 00 00 01 00 00 00
{10731} normal block at 0x0032F4B0, 20 bytes long.
Data: < C| > B8 AE 43 7C 01 00 00 00 01 00 00 00 01 00 00 00
thrdcore.cpp(311) : {174} client block at 0x0032F948, subtype c0, 68 bytes long.
Но когда завершается без ошибок, то все нормально!

Автор: Coocky 1.6.2005, 15:37
takedo
Цитата
Да я вообще хотел бы просто узнать как такие вещи делают?

http://www.firststeps.ru/dotnet/r.php?83
И далее там

Автор: takedo 1.6.2005, 15:38
только что от туда, не помогло.

Автор: Coocky 1.6.2005, 15:40
Цитата
Я и говорю, что все было в порядке, до тех пор как не начал из потока отрисовывать.

Дык может поток закрываешь, когда еще ненадо закрывать?

Автор: takedo 1.6.2005, 15:45
Можно получить ответ на такой вопрос: "Можно ли вызывать из рабочего потока функцию DrawItem объекта" типа так:
DWORD Potok(LPVOID lparam)
{
CJpDoc = pDoc = reinterpret_cast<CJpDoc*>(lParam);

if(!pDoc)return 1;
if(!pDoc->IsKindOf(RUNTIME_CLASS(CJpDoc)))return 2;

while(1)
{
pDoc->m_automats->ptr_button[1]->SetCondition(1);//или 2 или 3 ....
}
}

CButton1 : public CButton
{
public BYTE cond;
SetCondition(BYTE n){cond=n;GetColor(/*выбор цветов*/); Invalidate(/*вызов DrawItem*/)}
}


Добавлено @ 15:46
а закрываю я его в void CJpDoc::OnCloseDocument()
запускаю в BOOL CJpDoc::OnNewDocument()

Автор: Dreamer_0x01 2.6.2005, 15:39
Цитата

Detected memory leaks!
Dumping objects ->
{10733} normal block at 0x0032F658, 70 bytes long.
Data: < C| > B8 AE 43 7C 1A 00 00 00 1A 00 00 00 01 00 00 00
{10731} normal block at 0x0032F4B0, 20 bytes long.
Data: < C| > B8 AE 43 7C 01 00 00 00 01 00 00 00 01 00 00 00
thrdcore.cpp(311) : {174} client block at 0x0032F948, subtype c0, 68 bytes long.


А вот эта хрень выдается, когда ты память не освобождаешь занятую.
Как правило, это из-за того, что забываешь деструктор вызвать в каких-то крайних ситуациях.

Автор: takedo 4.6.2005, 14:08
Сенькю вери матч!
Однако, все проблемы были все-таки из за синхронизации, теперь все гуд!
Но!!!!!!!!!!!!! Вот чего не понятно: приложение SDI. Когда пытаюсь убить поток, который отрисовывает в CView при закрытии фрейма(крестик справа вверху), то все виснет. Может быть фрейм посылает WM_QUIT, а мой поток WM_PAINT они друг друга пережидают??? Кто - то знает чего происходит?
Я сделал по меню выход. Там убиваю поток, затем вызываю CFrameWnd::OnClose(); и все работает.
Так вот ещй проблема(будете смеятся): не получается во фрейме сделать SYSMENU только с кнопками максимизировать и минимизировать и без активной кнопки закрыть!!! Кто то может объяснить как это сделать? Только сперва попробуйте сами на SDI потом уже советуйте, пожалуйста... smile

Автор: Coocky 4.6.2005, 23:19
takedo
Цитата
Но!!!!!!!!!!!!! Вот чего не понятно: приложение SDI. Когда пытаюсь убить поток, который отрисовывает в CView при закрытии фрейма(крестик справа вверху), то все виснет

Не виснет, а поток не завершается.Проверь, как ты закрываешь его.
И вообще обработай закрытие в WM_ENDSESSION

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