Столкнулся с проблемой. В проге создается thread, который заполняет
VSFlexGrid. Параллельно основной поток обрабатывает события от грида. Для
синхронизации поставил critical section. В произвольный момент происходит
зависание. Написал тестики для VSFlexGrid, MSFlexGrid и ListView — все
аналогично. Вот кусок кода для ListView:
int CMultiThreadTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListView::OnCreate(lpCreateStruct) == -1)
return -1;
AfxBeginThread( MyThreadFunction, this ) ;
return 0;
}
UINT MyThreadFunction(LPVOID pParam)
{
CString buf;
CMultiThreadTestView *t = (CMultiThreadTestView *)pParam;
for ( UINT i=0; i<1000; i++ )
{
buf.Format("String %d", i+1);
t->cs.Lock();
CListCtrl &lst = t->GetListCtrl();
Sleep(100); //Чего-то делаем
lst.InsertItem(i, buf);
t->cs.Unlock();
}
return 0;
}
void CMultiThreadTestView::OnMouseMove(UINT nFlags, CPoint point)
{
cs.Lock();
//Чего-то делаем
cs.Unlock();
CListView::OnMouseMove(nFlags, point);
}
После зависания делаю Break в дибагере. Вижу 2 потока. Основной поток в
строке cs.Lock(); а другой — lst.InsertItem.
Поскажите, что не так!
Моя коннфигурация: WindowsXP sp2, Visual C++ sp6, Intel Pentium 4(3Ггц), 2Гб ОЗУ
01.08.06 09:25: Перенесено модератором из 'C/C++' — Odi$$ey
Здравствуйте, AndreyPavlov, Вы писали:
<...>
1) Объекты MFC классов нельзя передавать между потоками:
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
Передавать надо хендл окна, а в потоке использовать CWnd::FromHandle()
2) Лучше организовать обновление через посылку сообщений в основной поток:
int CMultiThreadTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListView::OnCreate(lpCreateStruct) == -1)
return -1;
AfxBeginThread( MyThreadFunction, this->GetSafeHwnd() ) ;
return 0;
}
UINT MyThreadFunction(LPVOID pParam)
{
CString buf;
CMultiThreadTestView *t = (CMultiThreadTestView *)CWnd::FromHandle((HWND)pParam);
for ( UINT i=0; i<1000; i++ )
{
buf.Format("String %d", i+1);
t->SendMessage(WM_UPDATE_LIST, static_cast<LPCTSTR>(buf), 0);
}
return 0;
}
В CMultiThreadTestView (кстати теперь его можно переименовать ) естественно завести обработчик WM_UPDATE_LIST. Вместо SendMessage также можно использовать PostMessage, но тогда надо позаботиться об выделении памяти под строку в потоке и ее освобождении в обработчике сообщения
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde