Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30

Странное падение в момент обработки сообщения

25.04.2011, 22:13. Показов 1465. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Имеется оконная программа, работающая с потоком. В программе запускается поток. Поток через PostMessage отправляет в Handle от окна (формы TForm) сообщение WM_USER. Сообщение отправляется практически сразу после создания потока (по результату сокращения внешних условий для воспроизведения ошибки). В классе окна прописан стандартным образом ловушка для сообщений:

C++
1
2
3
4
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER (WM_WINDOWPOSCHANGING, TMessage, WM_WindowPosChanging)
MESSAGE_HANDLER (WM_USER, TMessage, WM_User)
END_MESSAGE_MAP (TForm)
В момент обработки сообщения происходит падение. Стек падения см. на скриншоте. Во всём этом стеке единственным "моим" кодом является эта самая ловушка сообщений. Отладчик показывает на строку с WM_USER. После препроцессирования этой ловушки код выглядит следующим образом:

C++
1
2
3
4
virtual void __fastcall Dispatch(void *Message) { switch (((PMessage)Message)->Msg) {
case 0x0046: WM_WindowPosChanging(*((TMessage *)Message)); break;
case 0x0400: WM_User(*((TMessage *)Message)); break;
default: TForm::Dispatch(Message); break; } }
Если я правильно понимаю, то следующая по исполнению функция, вызванная из моего кода - это KiUserExceptionDispatcher. Однако глядя на препроцессированный код, я вижу, что в данной альтернативе switch'а есть только вызов метода WM_User и больше ничего. Каким образом мы попали в указанную функцию из ntdll? Как более широкий вопрос: в какую сторону надо копать для выяснения причины ошибки? Что означает такой стек падения?

Если между рождением потока и вызовом PostMessage поставить sleep с небольшой задержкой, то слома не происходит. Если поставить брекпоинт в данное место, то ошибки не происходит. В точке, соответсвующей case'у всё в порядке: this корректный, *Message корректно читается

Ну и как частный вопрос по Builder'у: как продизассемблировать мою функцию? В builder'е есть кнопка Disassemble, но она дизассемблирует только функцию, находящуюся на вершине стека
Миниатюры
Странное падение в момент обработки сообщения  
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
25.04.2011, 22:13
Ответы с готовыми решениями:

Падение производительности метода обработки изображения
Есть 2 метода, осуществляющие фильтрацию, они почти идентичны, однако один отрабатывает 7 секунд, второй 3 минуты. Не могу найти причину...

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

В какой момент появляются сообщения в console.log
Добрый день! Подскажите, в какой момент приходят сообщения, которые появляются в консоли браузера? Происходит ли это до отрисовки...

7
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.04.2011, 22:20  [ТС]
Цитата Сообщение от Evg Посмотреть сообщение
Если между рождением потока и вызовом PostMessage поставить sleep с небольшой задержкой, то слома не происходит
Хотя от момента создания потока до отправки сообщения у меня стоит контрольная печать, которая печатает в файл. И печать отрабатывает нормально. Т.е. от момента рождения потока и до отправки сообщения проходит довольно-таки значительное время (миллионы тактов, включая заходы в ОС). Поток создаётся через класс TThread
0
 Аватар для Maluda
1280 / 598 / 116
Регистрация: 18.08.2009
Сообщений: 832
26.04.2011, 01:30
В общем, я так и не понял проблему.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <IdBaseComponent.hpp>
#include <IdThreadComponent.hpp>
class TForm1 : public TForm {
__published: // IDE-managed Components
 
    TLabel *Label1;
    TLabel *Label2;
    TButton *Button1;
    TIdThreadComponent *IdThreadComponent1;
    
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall IdThreadComponent1Run(TIdThreadComponent *Sender);
 
private: // User declarations
 
public: // User declarations
    __fastcall TForm1(TComponent* Owner);
 
    BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, TMessage,OnWindowPosChanging)
        MESSAGE_HANDLER(WM_USER, TMessage, OnUser)
    END_MESSAGE_MAP(TForm);
 
    void OnWindowPosChanging(TMessage MSG1) {
        static int iTest = 0;
        Label1->Caption = "Changing " + IntToStr(iTest++);
    }
 
    void OnUser(TMessage MSG1) {
        Label2->Caption = MSG1.LParam;
    }   
};
 
void __fastcall TForm1::IdThreadComponent1Run(TIdThreadComponent *Sender) {
    static int iTest = 0;
    PostMessageA(this->Handle, WM_USER, 0, iTest++);
    Sleep(16);
}
 
void __fastcall TForm1::Button1Click(TObject *Sender) {
    if (IdThreadComponent1->Active) {
        IdThreadComponent1->Terminate();
    }
    else {
        IdThreadComponent1->Active = true;
    }
}
Cоздаётся поток, из него отправляются сообщения окну. Всё работает.
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
26.04.2011, 21:14
А не в самом ли обработчике WM_User проблема? В него заходит, или падает до него? Правда, как это связано со Sleep, тут вообще даже предположений нет.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.04.2011, 21:34  [ТС]
Да в том-то и дело, что ошибка из разряда нестабильных. Просто когда я PostMessage в моём случае подтащил как можно ближе к точке создания потока, то начало более-менее стабильно повторяться. Проблемы в своей программе я разгребу, если есть. Мне бы понять, что за стек такой и каким макаром мы залетаем в KiUserExceptionDispatcher. Эта некая фича, вызваная через аппаратное прерывание (при подкачке страницы, например) или что ещё за зверь такой. В гугле толком ничего не нашёл

Чем можно продизассемблировать функцию, чтобы посмотреть "свою" функцию хотя бы на предмет того, там какой-то call находится или ещё какая-нибудь ересь
0
2838 / 1647 / 254
Регистрация: 03.12.2007
Сообщений: 4,222
26.04.2011, 21:44
Цитата Сообщение от Evg Посмотреть сообщение
Чем можно продизассемблировать функцию, чтобы посмотреть "свою" функцию хотя бы на предмет того, там какой-то call находится или ещё какая-нибудь ересь
В Delphi есть View -> Debug Windows -> CPU, наверное, в Builder'е тоже должно быть?
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
26.04.2011, 22:04
как я лично понял, KiUserExceptionDispatcher-стартовая точка обработки любых SEH-исключений, оттого видать туда и залетаем.

А вот как отловить этот плавун...
Я бы попробовал делать лог хотя бы в тот же файл, что и печать. Типа перед вызовом PostMessage пишем "вызов", в момент входа в WM_User - "получено", можно еще добавить перед выходом что-нибудь. Вот только как сделать закрытие этого файла при ошибке. Попробовать все это завернуть в еще один try???

А насчет дизасма, по BC я полный 0, но может воспользоваться каким левым инструментом?. Типа, добавить для поиска в начало своей функции каку-нить строчку, в той же Olly найти эту строчку, и через ссылку на нее получить вход в свою функцию. Но неужели в BC нет нормального дизасма, вроде у них с самого начала с этим проблем не было.

Добавлено через 16 минут
И еще вот взбрела такая мысля - я бы проверил свой код на предмет наличия условий типа "тут можно не проверять результат - такого не может быть никогда". Обычно помогает, а то, чего не может быть, случается. Особенно что касается каких-то ресурсов, которые могут быть заняты (это я по поводу Sleep)
1
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.04.2011, 23:14  [ТС]
Цитата Сообщение от Somebody Посмотреть сообщение
В Delphi есть View -> Debug Windows -> CPU, наверное, в Builder'е тоже должно быть?
Я уже писал - дизассемблирует только функцию, находящуюся на вершине стека. В gdb можно просто делать up - down по стеку и дизассемблировать функцию в текущей активации стека. Наверняка ето и в builder'е есть, только нифига не втыкаю, как это сделать

Цитата Сообщение от kukuruku310 Посмотреть сообщение
И еще вот взбрела такая мысля - я бы проверил свой код на предмет наличия условий типа "тут можно не проверять результат - такого не может быть никогда". Обычно помогает, а то, чего не может быть, случается. Особенно что касается каких-то ресурсов, которые могут быть заняты (это я по поводу Sleep)
Скажем так, я не первый день программирую, а потому у меня весь код обтыкан ASSERT'ами. Из-за этого у меня вся отладка без отладчика проходит (ибо не нужен он в таких условиях). Собтсвенно поэтому и не научился до сих пор борландовским отладчиком пользоваться

Цитата Сообщение от kukuruku310 Посмотреть сообщение
Вот только как сделать закрытие этого файла при ошибке. Попробовать все это завернуть в еще один try???
С этим тоже проблем никаких. В файл печатаю через FILE* и делаю fflush - и печати не пропадают и нормально в файле оседают.

Цитата Сообщение от kukuruku310 Посмотреть сообщение
в момент входа в WM_User - "получено"
А вот до этого не додумался. Голова уже не варила. Это то, что нужно было сделать в обязательном порядке. Собственно, такая печать и вскрыла проблему. У меня посылка сообщений делается несколько раз подряд - воткнул чтобы более надёжно ошибка проявилась, да в процессе отладки опять-таки из-за закипания мозгов совсем забыл про то, что их несколько. Цикл должен был быть следующим: в потоке отправляем сообщение и ждём, пока оно будет отработано в главном процессе. После отработки сообщения поток продолжает работу. Такое последовательное исполнение сначала в потоке, потом в главном процессе, а потом опять в потоке, сделано на семафорах. И в этом месте я что-то накосячил. У меня реально одно наложилось на другое (т.е. нет последовательного исполнения).

Этот код у меня уже давно работает без проблем, а потому я считал его отлаженным. Видимо, просто проблема не проявлялась раньше. Где копать теперь понятно. Правда всё равно не понятно, почему наличие второго сообщения в очереди сообщений привело к такому крэшу.

Добавлено через 7 минут
Хотя нет... эффект наложения печатей произошёл из-за того, что я поставил печать в начале WM_User и в конце. А конечная печать происходит после освобождения семафора, так что она не в том месте стоит. После правильной расстановки печатей выглядит всё правильным. Первый цикл отрабатывает корректно. На второй раз в WM_User зашли, но оттуда уже не вышли. Но зацепка тем не менее есть, так что спасибо за идею, буду копать дальше

Добавлено через 13 минут
Ну и ещё раз на всякий случай. Правильно ли я работаю с семафором?

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* Стартовая инициализация */
Sem1 = CreateSemaphore (NULL, 1, 1, NULL);
Sem2 = CreateSemaphore (NULL, 0, 1, NULL);
 
/* Поток */
while (1)
{
  ДЕЙСТВИЕ1
  WaitForSingleObject (m_InSem1, INFINITE);
  PostMessage (Handle, WM_USER, 0, 0);
  WaitForSingleObject (m_InSem2, INFINITE);
  ДЕЙСТВИЕ3
}
 
/* Обработчик сообщения WM_USER в главном процессе */
ДЕЙСТВИЕ2
ReleaseSemaphore (m_InSem2, 1, NULL);
ReleaseSemaphore (m_InSem1, 1, NULL);
При такой организации будет последовательно исполняться: ДЕЙСТВИЕ1 - ДЕЙСТВИЕ2 - ДЕЙСТВИЕ3 - ДЕЙСТВИЕ1 - ДЕЙСТВИЕ2 - ДЕЙСТВИЕ3 .... Так?

Добавлено через 3 минуты
Ай да Пушкин, ай да сукин сын! Какой же я тупой! ДЕЙСТВИЕ1 формирует указатель, ДЕЙСТВИЕ2 этот указатель использует. Для подстраховки после использования указатель обнуляется. Но обнуление я поставил ПОСЛЕ ReleaseSemaphore. Вот блин протупил так протупил....

И святая истина, что когда начнёшь другому объяснять свой код, то начинаешь замечать в нём ошибки. А пока не объясняешь - нифига их не видно. В который раз убедился, что это так и в который раз не могу понять, почему так происходит
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
26.04.2011, 23:14
Помогаю со студенческими работами здесь

Обработки сообщения от кнопки
Добрый день! Создал кнопку CheckBoxStart, которая находится на панели PanelBasics PanelBasics =...

Telegram bot: как отправлять сообщения пользователю в определённый момент времени?
Как отправлять сообщения пользователю, в определённый момент времени?

Перенаправление / вывод сообщения после обработки формы
Как вывести сообщение с информацией после обработки введенных пользователем данных? Сейчас используется редирект на страницу...

Unity начинает медленно отрисовывать падение персонажа (Как бы проседает FPS, но только на падение)
Собственного говоря, всем здравствуйте! Я в юнити работаю очень редко, но всегда хотелось (как, думаю, и многим) написать собственную...

Найти момент сил M, действующие на шар в момент времени t =2 с после начала движения
Шар, радиус которого 15 R= см, масса 5 m= кг, движется вокруг неподвижной оси, проходящей через его центр. Уравнение движения шара имеет...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru