• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

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

    Запись на курс до 25 апреля. Получить промодоступ ...

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

  • Автор темы Guest
  • Дата начала
Статус
Закрыто для дальнейших ответов.
G

Guest

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

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

Код:
#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 столбце.
При чем, вызывается она с разных мест:

Код:
...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:
Код не мой, но баг не могу найти. У кого какие идеи?
 
A

AlexGin

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

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

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


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

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));
 
G

Guest

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

Код:
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) - не красиво!
Как иначе можна решить? Ваши предложения...
 
G

guest_from_minsk

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

Обучение наступательной кибербезопасности в игровой форме. Начать игру!