Проблема с CriticalSection
От: AndreyPavlov  
Дата: 01.08.06 05:13
Оценка:
Столкнулся с проблемой. В проге создается 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
Re: Проблема с CriticalSection
От: ekamaloff Великобритания  
Дата: 01.08.06 05:41
Оценка:
Здравствуйте, 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
Re: Проблема с CriticalSection
От: Аноним  
Дата: 01.08.06 05:45
Оценка:
Здравствуйте, AndreyPavlov, Вы писали:

Все просто, классический дедлок.
InsertItem представляет обертку над SendMessage.
SendMessage синхронная функция, которая ждет завершения обработки сообщения,
но сообщение не может быть обработано, так как в обработчике сообщений твоя
функция висит на локе.
Убери синхронизацию, в данном случае она не нужна — твой обработчик и обработчик
InsertItem будут вызваны в контексте одного потока.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.