Как "отловить" dead-lock?

Тема в разделе "MS Visual C++", создана пользователем Guest, 9 дек 2003.

Статус темы:
Закрыта.
  1. Guest

    Guest Гость

    Написал много CListCtrl в своей практике. Никогда не было проблем.
    Но сейчас в новом (большем) проекте, "наступил" на такой баг:

    В одном из многих больших диалогов создается маленький (2 x 9) CListCtrl:

    Код (Text):
    #define NUM_COLUMNS 2
    #define NUM_ITEMS  9

    ...Dlg::OnInitDialog():
    {................................
     int i;
     LV_COLUMN lvc;
     CRect rect;
     
     m_LargeImageList.Create(1, 18, ILC_COLOR, 1, 1);
     m_LSStatusListCtrl.SetImageList(&m_LargeImageList, LVSIL_NORMAL);
     m_LSStatusListCtrl.SetImageList(&m_LargeImageList, LVSIL_SMALL);

     lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
     m_LSStatusListCtrl.GetWindowRect(&rect);

     for(i = 0; i < NUM_COLUMNS; i++)
     {
       lvc.iSubItem = i;
       lvc.pszText = m_strColumnLabel[i];
       lvc.fmt = n_ColumnFmt[i];    
       lvc.cx = rect.Width() * n_ColumnWidth[i];
       m_LSStatusListCtrl.InsertColumn(i,&lvc);
     }

    // insert items

     LV_ITEM lvi;
     CString desc_str;

     for(i = 0; i < NUM_ITEMS; i++)
     {
       lvi.mask = LVIF_TEXT | LVIF_STATE;
       lvi.iItem = i;
       lvi.iSubItem = 0;
       desc_str.LoadString(n_ItemNames[i]);
       lvi.pszText = desc_str.GetBuffer(1);
       lvi.stateMask = LVIS_STATEIMAGEMASK;
       lvi.state = INDEXTOSTATEIMAGEMASK(1);

       m_LSStatusListCtrl.InsertItem(&lvi);
     }
    ...................
    }
    В нем кроме других "вещей" в Реал-time работает постоянно (часто) функция, которая меняет значения в 1 столбце.
    При чем, вызывается она с разных мест:

    Код (Text):
    ...Dlg::SetStatus()
    {
     CString sTmp1;
    // получаем значение sTmp1
     m_LSStatusListCtrl.SetItemText(0, 1, sTmp1):  
    // получаем значение sTmp1
     m_LSStatusListCtrl.SetItemText(1, 1, sTmp1);
    // получаем значение sTmp1
     m_LSStatusListCtrl.SetItemText(2, 1, sTmp1);
    // получаем значение sTmp1
    ....................................
     m_LSStatusListCtrl.SetItemText(8, 1, sTmp1);
    }
    Так вот, если открыть другой диалог в это время... - вся аппликация при этом подвисает "мертво"... :sad: CPU, при этом, не используется...
    Функция обновления вызывается в 2 местах, из диалогa... Pаботает постоянно, но "отцовство" запутанное...
    Код писался годами. Проэкт большой. Наследование запутанное. Очень много
    threads. Дебагировать сложно... :shuffle:
    Код не мой, но баг не могу найти. У кого какие идеи?
     
  2. AlexGin

    AlexGin Гость

    1) Если у тебя есть подозрения на функцию, что часто
    обновляет содержимое контрола - отключи ее (хотя бы для пробы)
    просто заблокируй комментариями. Это обычно помогает найти
    какой-то след проблемы.

    2) Попробуй заблокировать ImageList - посмотри на что будет
    влиять...

    3) Попытка хотя бы временно заменить этот контрол на что-то
    другое (пусть, для пробы, и не подходящее для User-a) так же
    может натолкнуть на полезную мысль.


    Так как контрол находится в диалоге, просмотри еще в
    редакторе ресурсов - все ли опции и режимы установлены
    корректно.
     
  3. marker

    marker Гость

    Мне кажется, стоит проанализовать все обработчики WM_PAINT - по крайней мере, все переопределения OnPaint в разных классах. Если какой-нибудь из них вызывает SendMessage (например, через SetItemText), то одно это может привести к подвисанию - был у меня давно подобный баг.

    Можно попробовать Spy++ - может быть, какое-то сообшение повторяется без конца, и не дает закончить обновление? Хотя 0% загруженности процессора говорит против этой возможности.

    Ну, и еще можно создать отдельный thread, который будет в цикле ждать сигнала и затем делать то, что сейчас делает Dlg::SetStatus, а сам Dlg::SetStatus будет только давать этот сигнал - т.е. сделать так, чтобы SetItemText никогда не вызывался ни из одного существующего thread'а - только из нового.

    Да, еще одно: в твоем коде Dlg::SetStatus SetItemText в качестве параметра дается CString. Хотя это и законно, по-моему, где-то я видел рекомендацию при обращении к Windows API писать в явной форме .GetBuffer(1) - то ли cast из CString в LPCSTR может как-то синхронизироваться, то ли еще что, не помню:
    m_LSStatusListCtrl.SetItemText(0, 1, sTmp1.GetBuffer(1));
     
  4. Guest

    Guest Гость

    В конце концов "лечил" так:

    Код (Text):
    MyDlg.h
    ...
    protected:
     afx_msg LRESULT SetState(WPARAM wParam, LPARAM lParam);
     DWORD m_nDlgThreadID;
    ...

    MyDlh.cpp

    BEGIN_MESSAGE_MAP...
    ...
     ON_MESSAGE(WM_USER_RESULT, SetState)
    ...
    END_MESSAGE_MAP()

    // в конструкторе диалогового класса
     m_nDlgThreadID = 0;

    BOOL ...::OnInitDialog()
    {
    ...
     m_nDlgThreadID = GetCurrentThreadId();
    ...
    }

    LRESULT MyDlg::SetState(WPARAM wParam, LPARAM lParam)
    {
     if (GetCurrentThreadId() != m_nDlgThreadID)
     {
       this->PostMessage(WM_USER_RESULT, 0, 0);
       return 0;
     }
    ..............................
    // что мы делаем обычно для SetState
     if (this)
     {    
       CString sTmp1;
    // получаем значение sTmp1
       m_LSStatusListCtrl.SetItemText(0, 1, sTmp1):  
    // получаем значение sTmp1
       m_LSStatusListCtrl.SetItemText(1, 1, sTmp1);
    // получаем значение sTmp1
       m_LSStatusListCtrl.SetItemText(2, 1, sTmp1);
    // получаем значение sTmp1
    ....................................
       m_LSStatusListCtrl.SetItemText(8, 1, sTmp1);
       return 0;
     }
    }
    Поскольку процесс получения значений 8 строк sTmp1 сравнительно "значительный"..., между строк при общем закрытии аппликации (при окрытом данном MyDlg диалоге) "застряет" - получаем ACCESS VIOLATIONS... :)

    Поставить перед каждым получениeм значения строк if (this) - не красиво!
    Как иначе можна решить? Ваши предложения...
     
  5. guest_from_minsk

    guest_from_minsk Гость

    Я тут сильно не пытался все проанализировать, но если логических ошибок нет, то попробуй использовать (если еще не) многопотоковую версию MFC. Модальный диалог блокирует вызывающий поток на обновления. Как вариант попробуй использовать модальный дилог на WinAPI без использования функций MFC.
     
Загрузка...
Статус темы:
Закрыта.

Поделиться этой страницей