Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Неизвлекаемое сообщение PeekMessage


Автор: Alexeis 28.11.2014, 13:23
Имеется код проверки сообщения в очереди
Код

DWORD res = MsgWaitForMultipleObjectsEx(WaitObjHandleList.size(), &WaitObjHandleList[0], chkTimeout,
                                                   QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);

...
if (res == WAIT_OBJECT_0 + WaitObjHandleList.size()) //сообщение пришло
            {
                ProcessMessage();
            }



И собственно код обработки сообщений

Код

    MSG msg;
    BOOL bRet = 0;
    do
    {
        bRet = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
        if (bRet == -1)
        {
            bRet = bRet;
            //handle the error and possibly exit
        }
        if (bRet > 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {

        }
    }
    while (bRet != 0);


Т.е. функция PeekMessage должна вызываться ТОЛЬКО если пришло сообщение в очередь потока. Однако после тыкания мышкой по диалогу приходят какие-то странные сообщения, которые не извлекает PeekMessage
Наличие их в очереди я проверяю при помощи

Код

DWORD res = GetQueueStatus(QS_ALLINPUT);


получаю код 0x00060000 что ровняется 0x00040000 | 0x00020000
Т.е. сообщения MouseDown и МоuseMove . Все бы ничего, да после появления таких сообщений цикл обработки сообщения зацикливается и сжирает 100% времени ядра. Т.е. по сути MsgWaitForMultipleObjectsEx  видит сообщение, а PeekMessage нет, при этом GetQueueStatus также его видит.

Автор: feodorv 28.11.2014, 15:38
Любопытно. А Ваша очередь сообщений не была ли присоединена к другому потоку?

Автор: Alexeis 28.11.2014, 15:46
Цитата(feodorv @  28.11.2014,  16:38 Найти цитируемый пост)
Любопытно. А Ваша очередь сообщений не была ли присоединена к другому потоку?

  Ситуация довольно хитрая. Это действительно обработчик сообщений дополнительного потока. В нем осуществляется работа с некоторым устройством. В нем же создается диалог ( WinAPI CreateDialog ) . Диалог имеет в качестве родителя Окно, которое создано в главном потоке. Соответственно через родителя сообщения не транслируются этому диалогу, а идут напрямую через очередь сообщений своего потока.
  Пока что ошибку провоцирую таким образом, что завешиваю на время главный поток и начинаю кликать мышкой по диалогу созданному в этом дополнительном потоке. После чего в очереди сообщений дополнительного потока появляются странные неизвлекаемые сообщения.

Автор: feodorv 28.11.2014, 15:52
Ага. 
Цитата
Функции GetMessage и PeekMessage проверяют флаги пробуждения только для вызывающего потока. Это значит, что потоки никогда не смогут извлечь сооб щения из очереди, присоединенной к другому потоку, включая сообщения для потоков того же процесса. 

http://wm-help.net/books-online/book/59464/59464-20.html. Как с этим быть, не знаю...

Автор: Alexeis 28.11.2014, 16:14
  Да, я пока искал ошибку наткнулся на эту ссылку. У меня именно так и происходит. В дополнительном потоке работает очередь обработки сообщений, эвентов, таймеров и асинхронных функций. Именно в ней и вызывается PeekMessage. При этом судя по коду возврата функции MsgWaitForMultipleObjectsEx (функция возвращает 2, при том что в списке 1 эвент и 1 Waitable Timer) это значит, что пришло сообщение. При этом есть также сработавший таймер, но вероятно функция MsgWaitForMultipleObjectsEx отдает приоритет сообщениям, а сигнал от таймера я вообще не вижу. Это как раз и указывает на то, что сообщение попав единажды в очередь не вычитывается никогда . Асинхронные вызовы я сразу отмел, так там код возврата из MsgWaitForMultipleObjectsEx другой.

Автор: Alexeis 11.2.2015, 13:22
  Если вдруг кому интересно, эта тема получила продолжение. Ошибку с неизвлекаемым сообщением я не устранил, устранил лишь возможность ее появления. В некотором роде прояснилась природа этих сообщений. Ситуация простая
1) Есть потока А, в нем создано окно верхнего уровня.
2) Есть поток Б, в нем создано дочернее окно, родителем которого является окно из пункта 1.
3) Пытаемся взаимодействовать из потока А с окном созданном в потоке В. 

В результате в поток В посылаются псевдосообщения. Эти сообщения действительно не вычитываются при помощи PeekMessage. Функция возвращает результат - отсутствие сообщения. Назначение этих сообщений просто пробудить поток. Никакой смысловой нагрузки они не несут. Если взаимодействие с окном происходит из своего потока, то лишних сообщений нет. В обычном состоянии приходит по одному такому сообщению на одну межпотоковую операцию. Это стандартное документированное поведение.
 На счет неизвлекаемых сообщений, скорее всего там дело не в том, что сообщения неизвлекаемые, а скорее всего имеет место зацикливание при взаимодействии 2х потоков.

Автор: Dem_max 16.2.2015, 08:06
Зачем создавать кучу потоков и в них создавать окна ?

Автор: Alexeis 17.2.2015, 10:28
Цитата(Dem_max @  16.2.2015,  09:06 Найти цитируемый пост)
Зачем создавать кучу потоков и в них создавать окна ?

  Чтобы избежать лишней синхронизации. Когда оконные операции производятся в главном потоке, то приходится ждать главный поток. С оконным интерфейсом иногда возникают всякие непредвиденные выкрутасы типа
  Модель -> Вид -> контроллер -> Модель. Уведомлять нужно синхронно. Если все запущенно в 2х потоках, то нередко ловлю дедлоки. В одном потоке все проще.

Автор: GremlinProg 22.2.2015, 18:06
Ну в общем случае - окна не для мультитрединга. Если надо разделить работу по потокам в окнах, то это уже плохая идея. Понимайте, что окна - это декоративный слой пирога (самый верхний). Работой должны заниматься простые потоки, с простой синхронизацией. Окна - лишь представление их результатов и/или исходных данных.

Автор: Alexeis 23.2.2015, 02:26
Цитата(GremlinProg @  22.2.2015,  19:06 Найти цитируемый пост)
Если надо разделить работу по потокам в окнах, то это уже плохая идея. Понимайте, что окна - это декоративный слой пирога (самый верхний).

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

Цитата(GremlinProg @  22.2.2015,  19:06 Найти цитируемый пост)
Понимайте, что окна - это декоративный слой пирога (самый верхний). Работой должны заниматься простые потоки, с простой синхронизацией. Окна - лишь представление их результатов и/или исходных данных. 

  Окна это не только представление. Если бы все так было просто, то не требовалось бы никакой синхронизации. В первом приближении так задача и была решена. Заводится таймер в потоке GDI он проверяет изменилось ли состояние и если изменилось, то обновляет. 
  Но проблема в том, что окна управляют процессами. На оснований действий пользователя запускаются команды. В любом случае должна работать последовательность.
  Интерфейс -> действие -> команда -> изменение модели -> окончание команды -> подтверждение действия -> уведомление пользователя. 
  Недопустимо чтобы действие пользователя ни к чему не привело, или не было никакой реакции на его действие. Если интерфейс реализовать в отдельном потоке, то код контроллера приходится реализовывать в том же потоке что и модель, а это уже означает целый геморрой. Нужно в этом потоке создавать очередь для команд, каждую команду создавать в виде отдельного объекта в куче, предусматривать механизмы для слежения за очередью, и т.д. и т.п. а в конце оказывается, что некоторые команды важнее других и если модели сказали стоп, беги, назад, лети, то не нужно выполнять стоп, беги, назад, а нужно сразу лететь, а может иногда нужно стоп, а иногда лети. 
  
  Синхронное исполнение, когда модель, контроллер и вид в одном потоке в 1000 раз упрощают всю работу.
Пользователь всегда может начать действие, проследить за исполнением текущего действия, или отменить текущую операцию. И синхронность никак не позволит ему начать несколько операций.

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

Автор: GremlinProg 23.2.2015, 19:15
Цитата(Alexeis @  23.2.2015,  04:26 Найти цитируемый пост)
Если бы все так было просто, то не требовалось бы никакой синхронизации.

Обычно так и происходит, т.е. - просто. Если уже получается "не просто", значит вы решаете чужую задачу. Подумайте, может стоит выделить какой-то простой протокол управления вашим ядром и уже к нему прикрутить GUI. Тогда GUI можно делать интерактивным или нет. Первую версию можно было бы сделать вообще синхронной. Думаю, надо стремиться к такой модульности программ, как раз, чтобы они были простыми.
Цитата(Alexeis @  23.2.2015,  04:26 Найти цитируемый пост)
Но проблема в том, что окна управляют процессами.

Окна - прослойка между пользователем и системой - интерфейс взаимодействия. Конечно, они могут быть сложными, но они не должны решать чужие задачи. Определить ошибку оч. просто: если работа GUI влияет на результаты работы программы, значит что-то уже сделано не так - отделяйте мух от котлет.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)