На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Затык с сообщениями, отправляется 2, приходит 1
Отправлено 2 сообщения (и оба True - проверено). Но! Выводится сообщение True (т.е. PeekMessage поймал сообщение). А дальше поток зависает на GetMessage. Но ведь в очереди есть ещё одно сообщение!!! Даже если заменить PM_REMOVE на PM_NOREMOVE, всё равно ничего не меняется (хоть PeekMessage и не должен вынимать даже первое сообщение).
В чём проблема-то? :wall:
p.s. Наличие TranslateMessage(Msg) и DispatchMessage(Msg) не влияет на ситуацию (собственно, и не должно).
ExpandedWrap disabled
    type
      TMyThread = class(TThread)
        Started: Boolean;
        procedure Execute; override;
      end;
     
    procedure TMyThread.Execute;
    var Msg: TMsg;
    begin
      PeekMessage(Msg, 0, 0, 0, PM_REMOVE);  // Создаём очередь сообщений
      Started := True;
      Sleep(1000);
      MessageBox(0, PChar(BoolToStr(PeekMessage(Msg, 0, 0, 0, PM_REMOVE), True)), '', MB_OK);
      GetMessage(Msg, 0, 0, 0);
      MessageBox(0, PChar(IntToStr(Msg.message)), '', MB_OK)
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      with TMyThread.Create(True) do
      begin
        Started := False;
        Resume;
        while not Started do Sleep(1);
        PostThreadMessage(ThreadId, WM_USER, 0, 0);
        PostThreadMessage(ThreadId, WM_USER+1, 0, 0)
      end
    end;
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Jin X
Так удаляются все сообщения.
https://msdn.microsoft.com/ru-ru/library/wi...6(v=vs.85).aspx
Цитата
PM_REMOVE
0x0001
Messages are removed from the queue after processing by PeekMessage



https://msdn.microsoft.com/ru-ru/library/wi...6(v=vs.85).aspx
Цитата
Unlike GetMessage, the PeekMessage function does not wait for a message to be posted before returning.

Специфика. Она всегда ждёт.

Тайм ауты делаем и всё работает.
ExpandedWrap disabled
    type
      TMyThread = class(TThread)
        Started: Boolean;
        procedure Execute; override;
      end;
     
    procedure TMyThread.Execute;
    var Msg: TMsg;
    begin
      PeekMessage(Msg, 0, 0, 0, PM_REMOVE);  // Ñîçäà¸ì î÷åðåäü ñîîáùåíèé
      Started := True;
      Sleep(100);
      MessageBox(0, PChar(BoolToStr(PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE), True)), '', MB_OK);
      GetMessage(Msg, 0, 0, 0);
      MessageBox(0, PChar(IntToStr(Msg.message)), '', MB_OK)
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      with TMyThread.Create(True) do
      begin
        Started := False;
        Resume;
        while not Started do Sleep(1);
        PostThreadMessage(ThreadId, WM_USER, 0, 0);
        sleep(10000);
        PostThreadMessage(ThreadId, WM_USER+1, 0, 0)
      end
    end;
Правильный обед должен состоять из 5 блюд приготовленных из 33 ингредиентов.
Вообще, я полагал, что он удаляет только те "messageS", которые идут до того, который ему нужен, а оказывается, что все...
Ну это ладно. Даже если я ставлю PM_NOREMOVE, результат тот же. Почему?
Мне нужно сделать что-то типа if PeekMessage then GetMessage (я хотел сделать это через один PeekMessage(PM_REMOVE), но раз он удаляет ВСЕ сообщения, но хотя бы через if-то должен работать!)
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Jin X
Немного пореверлся. У меня для вас 2 новости одна хорошая другая плохая.
Хорошая что в XE10.2 код работает как надо.
А вот плохая в D7 если окно NULL GetMessage кидает исключение, а D7 его перехватывает и направляет на обработчик сообщений основной формы.
И я не знаю как это исправить.
Правильный обед должен состоять из 5 блюд приготовленных из 33 ингредиентов.
Проблема в MessageBox... по ходу, он сжирает это сообщение как-то.
Убрал MessageBox'ы - всё заработало. Причём, PM_REMOVE удаляет только то сообщение, которое стоит в фильтре.
Скажем, если я посылаю сначала WM_USER+1, затем WM_USER и фильтрую WM_USER, то он именно его и удалит, а WM_USER+1 оставит!
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Цитата Jin X @
Проблема в MessageBox... по ходу, он сжирает это сообщение как-то.

:yes:
Внутри любого модального диалога крутится собственный цикл выборки сообщений, который собс-но и "сжирает" все сообщения
Цитата leo @
Внутри любого модального диалога крутится собственный цикл выборки сообщений, который собс-но и "сжирает" все сообщения
Да, это я уже понял :)
Тут один товарищ говорит, что взаимодействие с экраном нельзя делать из потока (типа не только не VCL). Что скажете?
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Jin X
Можно через WinAPI. Делать. Там для этого специальная функция есть - GdiFlush().

https://msdn.microsoft.com/en-us/windows/ha...onous-rendering
GdiFlush()
https://msdn.microsoft.com/en-us/library/wi...4(v=vs.85).aspx

leo
А почему тогда в XE рабтает?
Правильный обед должен состоять из 5 блюд приготовленных из 33 ингредиентов.
Цитата Pavia @
А вот плохая в D7 если окно NULL GetMessage кидает исключение, а D7 его перехватывает и направляет на обработчик сообщений основной формы.
Не понимаю вообще, с какой стати исключение возникает? У меня на 7 ничего такого не происходит...
Это прям с моим кодом происходит?

Добавлено
Вот, кстати...
ExpandedWrap disabled
    type
      TMyThread = class(TThread)
        Started: Boolean;
        procedure Execute; override;
      end;
     
    procedure TMyThread.Execute;
    var
      Msg: TMsg;
      Res: Boolean;
      Msg1, Msg2: Integer;
    begin
      PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);  // Ñîçäà¸ì î÷åðåäü ñîîáùåíèé
      Started := True;
      Sleep(1000);
      Res := PeekMessage(Msg, 0, WM_USER, WM_USER, PM_REMOVE);
      GetMessage(Msg, 0, WM_USER+1, WM_USER+1);
      Msg1 := Msg.message;
      GetMessage(Msg, 0, 0, 0);
      Msg2 := Msg.message;
      MessageBox(0, PChar(BoolToStr(Res, True)+' '+IntToStr(Msg1)+' '+IntToStr(Msg2)), '', MB_OK)
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      with TMyThread.Create(True) do
      begin
        Started := False;
        Resume;
        while not Started do Sleep(1);
        PostThreadMessage(ThreadId, WM_USER+2, 0, 0);
        PostThreadMessage(ThreadId, WM_USER+1, 0, 0);
        PostThreadMessage(ThreadId, WM_USER, 0, 0);
      end
    end;

Выдаёт True, 1025, 1026. Т.е. из очереди удаляется (хотя в PeekMessage, хоть GetMessage) только то сообщение, которое указано в фильтре, причём одно (это видно, если в PeekMessage сбросить фильтр в 0).

Добавлено
Цитата Pavia @
А почему тогда в XE рабтает?
Я сейчас залез через дебагер в MessageBox, там действительно этот цикл крутится, только через PeekMessage зачем-то, а потом уходит на WaitMessage.
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Цитата Jin X @
Это прям с моим кодом происходит?

Это прям внутри GetMessage() происходит. Она сверяет хэндел окна с нулём и если оно 0, то кидает исключение. D7 его даже не кажет оно там жёстко запрятано в system.pas.
Правильный обед должен состоять из 5 блюд приготовленных из 33 ингредиентов.
Цитата Pavia @
Можно через WinAPI. Делать. Там для этого специальная функция есть - GdiFlush().
Для чего, "для этого"? Если я вызываю MessageBox, мне GdiFlush не нужен. Если создаю окно - тоже.
А всякие специфические рисования – это уже другое дело.
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Цитата Pavia @
Это прям внутри GetMessage() происходит. Она сверяет хэндел окна с нулём и если оно 0, то кидает исключение. D7 его даже не кажет оно там жёстко запрятано в system.pas.
Странно, у меня такого не происходит... Прикрепи свой код сюда вместе с EXE-шником.

Вот это выдаёт исключения?
Прикреплённый файлПрикреплённый файлTest.rar (159,89 Кбайт, скачиваний: 5)
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Jin X
Цитата Jin X @
Для чего, "для этого"?

Ты спросил про VCL и экран.
Цитата Jin X @
Тут один товарищ говорит, что взаимодействие с экраном нельзя делать из потока (типа не только не VCL). Что скажете?

Я ответил что с экраном взаимодействовать можно. Но для этого надо применять GdiFlush()
VCL не использует GdiFlush. Поэтому VCL следует оборачивать в Synchronize - он вызывает функцию из основного потока.

Что касается окошек из другого потока. То тут я не в курсе. Но большинство оконных функций (WinAPI) работает на сообщениях и они считаются потоко безопасными.


Цитата Jin X @
Странно, у меня такого не происходит... Прикрепи свой код сюда вместе с EXE-шником.

Твой код из первого сообщений поставь бряк на GetMessage(Msg, 0, 0, 0);
И по нажимай F7 - до тех пор пока код не выйдет из этой функции.
Сообщение отредактировано: Pavia -
Правильный обед должен состоять из 5 блюд приготовленных из 33 ингредиентов.
Там у меня 2 раза "не" по ошибке :)
Цитата Pavia @
VCL не использует GdiFlush. Поэтому VCL следует оборачивать в Synchronize - он вызывает функцию из основного потока.
Ну там с VCL я так понял основная проблема в том, что он не реентерабельный, включая отсутствие работы с критическими секциями (не копался, но вроде как так).

Цитата Pavia @
И по нажимай F7 - до тех пор пока код не выйдет из этой функции.
А если не дебажить, исключения не будет?
Tell me would you kill to save a life?
Tell me would you kill to prove you're right?
Crash, crash, burn, let it all burn
This hurricane's chasing us all underground...
Скрытый текст
Цитата Jin X @
проблема в том, что он не реентерабельный, включая отсутствие работы с критическими секциями (не копался, но вроде как так).

Критические секции ведут к дедлокам. Спинлоки в этом плане как-то по понятие. Но тоже народ тоже не задумывается о дедлоках. Поэтому они тоже приводят к дедлокам.

Тогда как же сделать потокобезопасное приложение? теория на этот счёт говорит просто если у каждого потока будут свои данные то код будет потокобезопасен.

Как сделать что-бы у каждого были свои данные? Сообщения. сообщения это данные которые копируются каждые своему потоку.

Хотя вот такие вот выкрутасы D7 вымораживают. Лучше наверно реализовать свою очередь сообщений.

Классы VCL - потока не безопасен по тому что это общий ресурс(общие классы), а методы не защищены.

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

Но лично я решаю проблемы архитектурно шаблон генерал-подчинённый. Там дедлоки исключены.

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

Есть и второй способ уйти на низкий уровень. Пул потоков, и собственные примитивы синхронизации.
Правильный обед должен состоять из 5 блюд приготовленных из 33 ингредиентов.
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:


Рейтинг@Mail.ru
[ Script Execution time: 0,1666 ]   [ 22 queries used ]   [ Generated: 22.09.17, 11:49 GMT ]