Перейти к содержанию

Очистка очереди сообщений WinAPI


Antonshka

Рекомендуемые сообщения

Привет всем, подскажите, как удалить из очереди сообщений потока определенное сообщение/сообщения? Кто-нибудь игрался с этим? Что-то как-то темно все с этим в интернете.

 

Ситуация примерно такая:

- Поток A создал кнопку.

- При клике на эту кнопку, поток A создал поток Б.

- Поток Б через 30 секунд запостит (используя PostMessageW) в очередь сообщений потока A специальное мною определенное сообщение. Запостит и завершится.

- Однако, я передумал, и захотел отменить поток Б. Поток А, спустя 29.99 секунд после создания потока Б, идет и выполняет функцию отмены.

 

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

Я же хочу, чтобы поток А, в функции отмены, дождался принудительного завершения потока Б (SetEvant, WaitForSigleObject). Затем, в этой же функции отмены, поток А проверяет свою очередь сообщений, и удаляет из нее возможное в ней сообщение от потока Б.

Затем, поток А, вернется из функции отмены в MessageLoop функцию, и когда вызовет GetMessage, найдет что сообщения от потока Б уже нет. Значит оно не исполниться.

Ссылка на комментарий
Поделиться на другие сайты

В цикле GetMessage/DispatchMessage с возвратом в очередь всех сообщений, которые не совпадают с тем, что тебе нужно. Но осуществлять подобное средствами очереди сообщений винды - имхо, бред.

Ссылка на комментарий
Поделиться на другие сайты

57 минут назад, Xipho сказал:

В цикле GetMessage/DispatchMessage

В главном MessageLoop приложения? В этом?

Спойлер
while ((getMessageResult = GetMessageW(&msg, NULL, 0, 0)) != 0)	{
  if (getMessageResult == -1) {
    break;
  }
  else {
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
  }
}

 

 

1 час назад, Xipho сказал:

Но осуществлять подобное средствами очереди сообщений винды - имхо, бред.

Я не понял этот момент. Что такое "средства очереди сообщений винды"? Это функции типа GetMessage/PeekMessage?

Осуществлять удаление этими функциями бред? Тогда какими не бред?

Ссылка на комментарий
Поделиться на другие сайты

13 часов назад, Antonshka сказал:

Что такое "средства очереди сообщений винды"?

Это то, на чем построено всё функционирование оконной системы в винде.

 

13 часов назад, Antonshka сказал:

Осуществлять удаление этими функциями бред? Тогда какими не бред?

Конечно, бред. Потому что положенное в очередь сообщение будет дожидаться обработки по порядку (в общем случае) поступления. FIFO принцип. То есть, чтобы добраться до последнего сообщения, нужно вычитать все предыдущие. Ну и плюс вычитка сообщений всё-таки предполагается в основном потоке приложения. А в том кейсе, что ты описал, это не выглядит как FIFO, так как есть дополнительные условия и желание изымать сообщение из очереди при определенных обстоятельствах. Отсюда я делаю один вывод - тебе нужно что-то вроде буферного хранения сообщений, раз они могут быть отменены. Ну и система отложенной постановки сообщений из этого буферного хранения в виндовую очередь.

Наверное, ты это читал, но скину на всякий случай: https://docs.microsoft.com/ru-ru/windows/win32/winmsg/about-messages-and-message-queues#message-routing

Ссылка на комментарий
Поделиться на другие сайты

5 часов назад, Xipho сказал:

Наверное, ты это читал, но скину на всякий случай: https://docs.microsoft.com/ru-ru/windows/win32/winmsg/about-messages-and-message-queues#message-routing

Вчера читал всю эту статью. Также про функции. Также на других сайтах.

 

5 часов назад, Xipho сказал:

Конечно, бред. Потому что положенное в очередь сообщение будет дожидаться обработки по порядку (в общем случае) поступления. FIFO принцип. То есть, чтобы добраться до последнего сообщения, нужно вычитать все предыдущие. Ну и плюс вычитка сообщений всё-таки предполагается в основном потоке приложения. А в том кейсе, что ты описал, это не выглядит как FIFO, так как есть дополнительные условия и желание изымать сообщение из очереди при определенных обстоятельствах.

Все равно не понял почему работа с очередью сообщений это бред.

Поток А - это главный GUI поток, он создал кнопку, и он создал поток Б.

Поток А вызывает функцию "отмена", в которой закрывает поток Б, ждет его окончания, и зачищает свою же очередь сообщений, перед тем как выйти из функции "отмена". То есть зачистка сообщений производится главным потоком А.

Вот так примерно

Спойлер
VOID PopupMenu::clearMessageQueueFromUserMessages() {
  MSG msg{ 0 };
  PopupMenu* currentPopupMenu = rootPopupMenu;
  while (currentPopupMenu) {
    if (currentPopupMenu->hWnd) {
      std::vector<MSG> messagesToReturn;
      while (PeekMessageW(&msg, currentPopupMenu->hWnd, 0, 0, PM_REMOVE)) {
        switch (msg.message)
        {
          case WM_USERCREATEPOPUPMENUWINDOWBYDELAY:
            break;
          default:
            messagesToReturn.push_back(msg);
            break;
        }
      }
      if (messagesToReturn.size()) {
        std::ranges::reverse_view reverseView{ messagesToReturn };
        for (auto& messageToReturn : reverseView) {
          PostMessageW(currentPopupMenu->hWnd, messageToReturn.message, messageToReturn.wParam, messageToReturn.lParam);
        }
      }
    }
    currentPopupMenu = currentPopupMenu->childPopupMenu;
  }
}

 

Сообщения засовываются обратно в очередь в правильном порядке. Будет как и было, в FIFO.

 

5 часов назад, Xipho сказал:

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

Идея интересная, но по моему не реализуемая. Буфер создать не проблема. Пусть поток Б заполняет его для потока А.

 

Вот ситуация без отмены потока Б.

- Поток А создал поток Б.

- Поток А вернулся в MessageLoop, вызвал GetMessage, GetMessage обнаружил что новых сообщений нет, и поэтому Поток А ушел в спячку.

- Поток Б завершился сам, после 30 секунд, и заполнил буфер.

Но поток А спит, он не может понять что нужно обработать буфер. Нужен кто-то кто его разбудит. Это не может быть поток Б, иначе зачем тогда нужен буфер. Значит это Поток С, который пусть будет создан вместе с потоком Б. Тогда, Поток С, увидев что поток Б завершился сам, вызывает (PostMessageW) поток А, чтобы тот обработал буфер. Но где-то в этот самый момент, я передумал, хочу отменить обработку. Для этого Поток А идет и отменяет Поток С, но он не успел, Поток С уже запостил сообщения из буфера. Ситуация повторилась, стала как и с потоком Б.

Значит нужно обязательное удаление сообщений из потока А самим потоком А.

 

Пока что-то иногда вылазят ошибки. Нужно разбираться.

Ссылка на комментарий
Поделиться на другие сайты

4 минуты назад, Antonshka сказал:

Все равно не понял почему работа с очередью сообщений это бред.

Потому что ты хочешь изымать из этой очереди сообщения выборочно. Очередь сообщений винды под это не затачивалась. Чтобы извлечь одно сообщение, тебе надо вычитать все предыдущие и снова их положить в очередь. Разве это не бред? 

 

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

 

 

Ссылка на комментарий
Поделиться на другие сайты

17 минут назад, Xipho сказал:

Чтобы извлечь одно сообщение, тебе надо вычитать все предыдущие и снова их положить в очередь. Разве это не бред?

Ну вообще, наверно бред. Я бы хотел способ попроще. Способ удалить одно сообщение.

Но что я могу сделать, так устроили Microsoft.

Даже вот сейчас, я нашел баг, - в какой то момент PeekMessage уходит в бесконечный цикл, из кода выше. Видимо система начинает постить какое-то сообщение беспрестанно. И вот теперь новый костыль, - искать как заблокировать очередь, или сделать ее SnapShot, и работать уже с ним.

То WM_NCLBUTTONUP не ловится процедурой, потому что так устроено окно, то это, то то. Куча костылей.

 

24 минуты назад, Xipho сказал:

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

Это PopupMenu. Реализация задержки появления дочернего PopupMenu. Навел на пункт меню, но окно показывается только спустя несколько секунд. А если отвел курсор с пункта, то таймер должен отключится, и окно не должно появиться. Вот и вся задача.

Таймеры это дно, у них наименьший приоритет. Потому я использую потоки, для задержки. Поток-таймер не должен сам создавть окно, поэтому он посылает сообщение главному потоку. Но посылка через SendMessage приводит к DeadLock'y. Я использую PostMessage.

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Потому я использую потоки, для задержки

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

Ссылка на комментарий
Поделиться на другие сайты

33 минуты назад, Xipho сказал:

что-то вроде местечкового планировщика, почитай, как их обычно пишут.

Что-то ничего не нашел в интернете. Поиск выдает планировщик Windows.

 

35 минут назад, Xipho сказал:

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

Главный поток приложения тоже простаивает, когда нет сообщений. Да и другие потоки, тоже случается что засыпают.

А вообще, что я сделаю. Такова жизнь. Таймеры не подходят, из-за задержек. Можно подумать над тем чтоб поток создавался в момент создания окна родителя PopupMenu, и удалялся после его закрытия.

  • Печалька 1
Ссылка на комментарий
Поделиться на другие сайты

5 часов назад, Xipho сказал:

Потому что ты хочешь изымать из этой очереди сообщения выборочно. Очередь сообщений винды под это не затачивалась. Чтобы извлечь одно сообщение, тебе надо вычитать все предыдущие и снова их положить в очередь. Разве это не бред?

Хорошая новость, - оказывается все намного проще. Вначале это показали тесты, а теперь и более внимательное чтение MSDN.

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

PeekMessage

Спойлер

During this call, the system dispatches (DispatchMessage) pending, nonqueued messages, that is, messages sent to windows owned by the calling thread using the SendMessage, SendMessageCallback, SendMessageTimeout, or SendNotifyMessage function. Then the first queued message that matches the specified filter is retrieved. The system may also process internal events. If no filter is specified, messages are processed in the following order:

  • Sent messages
  • Posted messages
  • Input (hardware) messages and system internal events
  • Sent messages (again)
  • WM_PAINT messages
  • WM_TIMER messages

Нужно лишь указать фильтр. У меня это

while (PeekMessageW(&msg, currentPopupMenu->hWnd, WM_APP + 1, WM_APP + 5, PM_REMOVE)) {

 

Я запихал сообщения в очередь

Спойлер
PostMessageW(thisPopupMenu->hWnd, WM_USERSetIcon, 0, 0);
PostMessageW(thisPopupMenu->hWnd, WM_USERGetIcon, 0, 0);
PostMessageW(thisPopupMenu->hWnd, WM_CTLCOLORSTATIC, 0, 0);
PostMessageW(thisPopupMenu->hWnd, WM_USERIsWindowVScrollActive, 0, 0);
PostMessageW(thisPopupMenu->hWnd, WM_USERPopupMenuDestroyTreeOfFLoatPopupMenu, 0, 0); //Это и все сообщения выше имеют номер сообщение выше WM_APP + 5
PostMessageW(thisPopupMenu->hWnd, WM_USERPopupMenuCreatePopupMenuByDelay, 0, 0); //WM_APP + 5
PostMessageW(thisPopupMenu->hWnd, WM_USERSetDCFontColor, 0, 0); //Это и все сообщения ниже имеют номер сообщение выше WM_APP + 5
PostMessageW(thisPopupMenu->hWnd, WM_USERIconChanged, 0, 0);
PostMessageW(thisPopupMenu->hWnd, WM_CTLCOLOR, 0, 0);
PostMessageW(thisPopupMenu->hWnd, WM_CTLCOLOREDIT, 0, 0);

 

, и только WM_APP + 5 удалилось, как показала консоль-отладчик. То есть сообщение WM_APP + 5 было не в начале очереди, однако нормально удалилось.

Буду использовать один специальный поток на родителе PopupMenu. Все дочернии окна, их появление/скрытие, будут управляться им. Думаю это хорошая схема.

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

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

Ссылка на комментарий
Поделиться на другие сайты

2 часа назад, Xipho сказал:

Подумай над тем, как организовать отложенные задания. Если не получится самостоятельно - приходи, подскажу пару вариантов, которые могут тебе пригодиться.

Что за отложенные задания? Не могу ничего найти на них.

Ссылка на комментарий
Поделиться на другие сайты

24 минуты назад, Antonshka сказал:

Что за отложенные задания? Не могу ничего найти на них.

А если не искать, а подумать? Отложенные задания - это как раз то, про что ты писал выше. Например, нажал кнопку, но сработала она не сразу, а через какой-то промежуток времени. Ты для этого делаешь задержку в отдельном потоке, но подумай, как это можно сделать по-другому. Можно посмотреть примеры, как в винде организован отложенный вызов процедур (Deferred Procedure Call), и сделать по аналогии. Но я бы порекомендовал подумать над задачей самостоятельно, это будет неплохой прокачкой скилла, как мне кажется. И еще раз. Создавать поток только для реализации задержки - это бред, не делай так.

Ссылка на комментарий
Поделиться на другие сайты

5 часов назад, Xipho сказал:

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

Это понятно. Я про функции, которые управляют этими заданиями. Создают их, удаляют.

 

5 часов назад, Xipho сказал:

Можно посмотреть примеры, как в винде организован отложенный вызов процедур (Deferred Procedure Call), и сделать по аналогии.

Посмотрел, ничего не понятно. Что-то на уровне драйверов.

 

5 часов назад, Xipho сказал:

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

Подумал. Есть еще вариант с ThreadPool.

CreateTimerQueueTimer. Но там может возникнуть ситуация, что создастся новый поток.

Спойлер
WT_EXECUTELONGFUNCTION
0x00000010
The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.

 

Еще есть мультимедийным таймер, более точный.

Но все это оверинженеринг. Поток на родителя, и все.

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

4 часа назад, Antonshka сказал:

Посмотрел, ничего не понятно

https://blog.andreiavram.ro/job-scheduler-cpp/ 
Если не зайдет, гугли writing simple job scheduler c++

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

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Xipho сказал:

https://blog.andreiavram.ro/job-scheduler-cpp/ 
Если не зайдет, гугли writing simple job scheduler c++

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

Ну да, у него основа std::thread. Я кстати почему-то не склонен к std::thread. Предпочитаю beginthreadex.

Хотя std::vector, std::wstring, очень приветствую.

 

Скажи название функций, этого таинственного планировщика.

 

По логике, - должен быть "кто-то", кто разбудить главный GUI поток А. Который засыпает в функции GetMessage. Кто-то кто пошлет в очередь сообщений новое Post сообщение. Или кто-то кто пошлет сообщение Send-типа, что также разбудит Поток А, обойдя очередь.. В любом случае, кто-то должен разбудить Поток А через и только через сообщение. Иначе поток не проснется.

Таймер, - нет. Другой поток, - нет. DCP, - нет, там куча заморочек. Не представляю что еще способно разбудить Поток А. Таинственный планировщик? Но не лежит ли в его основе ThreadPool, вообще манипуляция своими собственными потоками?

Ссылка на комментарий
Поделиться на другие сайты

2 часа назад, Antonshka сказал:

GetMessage

а почему бы не воткнуть туда PeekMessage?🙂Ну и std thread довольно удобная штука, а в отличие от виндовых функций ещё и кроссплатформенная. Зря не пользуешься.

2 часа назад, Antonshka сказал:

Таймер, - нет

почему?

2 часа назад, Antonshka сказал:

Другой поток

не хочешь поток - используй PeekMessage

Ссылка на комментарий
Поделиться на другие сайты

9 часов назад, Antonshka сказал:

Скажи название функций, этого таинственного планировщика.

Да в смысле название функций? Самописный планировщик.

Просто грамотно организованный, чтобы не использовать кучи спящих потоков.

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

Ссылка на комментарий
Поделиться на другие сайты

8 часов назад, youneuoy сказал:

а почему бы не воткнуть туда PeekMessage?

В главный MessageLoop? Там лучше использовать GetMessage, чтобы не было потребления процессорного времени в отсутствии сообщений.

8 часов назад, youneuoy сказал:

Ну и std thread довольно удобная штука, а в отличие от виндовых функций ещё и кроссплатформенная. Зря не пользуешься.

_beginthreadex использую из-за совместимости с CRT функциями. Не знаю как в этом плане ведет себя std::thread, скорее всего, по логике, std::thread должна быть также совместима. Но, так как в я пока не чувствую себя ущемленным при использоании _beginthreadex , я не перехожу на std::thread.

Кроссплатформенность мне пока не по карману, иначе нужно весь код писать в таком стиле.

 

8 часов назад, youneuoy сказал:

почему?

Мне известно только 3 вида таймера.

- Стандартный таймер (WM_TIMER Post сообщение). Он не подходит. Неизвестно когда до него дойдет очередь, а мне нужен точный интервал. Плюс из-за него подвисает главный поток, в котором он обрабатывается, незначительно, но все же. Даже если для таймера использовать свою отдельную процедуру.

- Мультимедийный таймер. Он тоже не подходит. Он устарел. Плюс для обработки своей процедуры он использует свой поток.

- CreateTimerQueueTimer. Но там может возникнуть ситуация, что создастся новый поток. Но зачем мне это, я могу тогда сам создать поток.

 

8 часов назад, youneuoy сказал:

не хочешь поток - используй PeekMessage

Нет, я хочу использовать другой поток. Один поток на все дерево PopupMenu. Он контролирует задержки, плавность появления/скрытия. Он создается и удаляется только для главного родительского PopupMenu окна. Но, @Xipho говорит что это не лучший вариант.

 

1 час назад, Xipho сказал:

Да в смысле название функций? Самописный планировщик.

Просто грамотно организованный, чтобы не использовать кучи спящих потоков.

Понятно, я думал что это какой-то предопределенный механизм WinAPI.

А как он будет устроен, этот самописный планировщик. Что из себя он будет представлять? Это какой-то отдельный поток, который создается в начале работы приложения, и удаляется после его завершения? И например у него есть буферная очередь с заданиями. Опиши вкратце его схему. Мне уже не столько интересно это для проекта, сколько просто, для себя, что ты там такое придумал, чего я не нашел ни в интернете ни у себя в голове.

 

1 час назад, Xipho сказал:

В край, конечно, можно упороться и по PeekMessage, но лично моё мнение - это изврат.

Как понять по PeekMessage? Это то что предлагал выше @youneuoy? Даже если воткнуть вместо GetMessage, PeekMessage, то что это меняет? Кто подаст команду/сообщение в очередь сообщений Потока А? Ведь в этом вся суть проблему, - кто будет инициатором для главного потока. Главный поток только имеет право создавать окна, по задумке.

 

Использовать PeekMessage чтобы поток не засыпал? Ну хорошо, используем, поток не спит, а дальше что? Кто отсчитывает интервал, кто подает нужное сообщение. Сам Поток А, используя что-то вроде GetTickCount? Что-то так себе такая схема.

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

54 минуты назад, Antonshka сказал:

Мне уже не столько интересно это для проекта, сколько просто, для себя, что ты там такое придумал, чего я не нашел ни в интернете ни у себя в голове.

Да ничего такого я не придумал, это обычный механизм. Тот же самый event loop в рамках одного потока. Так работал в кишках JS до того, как наконец-то стал много поточным, так работает еще куча всего всякого. И это оптимальный механизм, на мой взгляд (да и не только на мой).

  • Понравилось 1
Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

В главный MessageLoop? Там лучше использовать GetMessage, чтобы не было потребления процессорного времени в отсутствии сообщений.

в отсутствии сообщений процессорное время у тебя отдельный поток будет потреблять(и кажется он будет не один)🙂Делай пару десятков обновлений в секунду, это будет потреблять самый мизер и в этом же цикле ты сможешь устанавливать нужные тебе тайминги и т.п.(как хипхо написал, это удобно когда приложуха лёгкая, а у тебя именно такая). 

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, youneuoy сказал:

в отсутствии сообщений процессорное время у тебя отдельный поток будет потреблять(и кажется он будет не один)

Отдельный поток будет потреблять самую малость времени сидя на WaitForSingleObject.

Цитата

The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters an efficient wait state. The thread consumes very little processor time while waiting for the object state to become signaled or the time-out interval to elapse.

Это время будет уходить лишь на проверку освободился ли объект событие. Далее поток не будет занимать процессорное время. То есть если поток ждет 3 секунды, он не тратит все эти 3 секунды зря. Он просто уступает время другим потокам в системе.

Raymond Chen

 

То есть я про то что отдельный поток по моему мнению лучше чем система с PeekMessage в MessageLoop. Пускай PopupMenu сам отвечает за себя, вообще любой элемент которому нужен таймер, пусть сам его и создает, в виде потока.  Главный поток должен быть абстрагирован от всех этих замеров прошедшего времени, проверки есть ли отложенные задания для все контролов библиотеки для которых это предусмотрено. Зачем нужна эта холостая проверки всех этих отложенных заданий, в случае если ни один контрол пока его не требует.

 

2 часа назад, Xipho сказал:

Да ничего такого я не придумал, это обычный механизм. Тот же самый event loop в рамках одного потока. Так работал в кишках JS до того, как наконец-то стал много поточным, так работает еще куча всего всякого. И это оптимальный механизм, на мой взгляд (да и не только на мой).

В рамках одного главного GUI потока? То есть использование PeekMesage вместо GetMessage для постоянной работы потока?

До конца я не понял схему, все равно. Объясни на конкретном примере, на куске кода, если не трудно. На словах мне иногда трудно понять о чем идет речь.

 

1 час назад, youneuoy сказал:

в отсутствии сообщений процессорное время у тебя отдельный поток будет потреблять(и кажется он будет не один)

Вот еще на одного сайте нашел

Спойлер

WaitForSingleObject в заблокированном состоянии вообще не потребляет процессора до тех пор пока объект ядра не придет в засигналенное состояние (т.о. проверка условия выхода из цикла делается 1 раз, правда в другом месте, там где происходит измениние состояния семафора), а Sleep раз в милисекунду пробуждает ваш поток (все равно через ядро) и потребляет ресурсы (т.е. проверка выхода из цикла делается 1 раз в милисекунду и срабатывает за все это время 1 раз).  

Это из Рихтера

Спойлер

Spinlocks assume that the protected resource is always accessed for short periods of time. This makes it more efficient to
spin and then transition to kernel mode and wait. Many developers spin some number of times (say 4000), and if access to
the resource is still denied, the thread transitions to kernel mode, where it waits (consuming no CPU time) until the
resource becomes available. This is how critical sections are implemented.

 

Изменено пользователем Antonshka
Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Вот еще на одного сайте нашел

если очень хочешь, используй WaitForSingleObject, CreateWaitableTimer или любую другую вещь в качестве замены для sleep🙂И задержка для sleep как-то вроде настраивается(но не всеми системами поддерживается, и вообще это бесполезная для написания подобных библиотек инфа). Но смысла в этом мало - код усложняешь, голову себе ерундой забиваешь, а выигрыш в скорости самый минимальный(ты его более чем компенсируешь косяками, возникшими вследствие этой неуместной оптимизации).

1 час назад, Antonshka сказал:

Главный поток должен быть абстрагирован

Ты планировщик можешь хоть в основной поток, хоть в дополнительный воткнуть. Следует абстрагироваться от таких загонов, как абстрагирование, WaitForSingleObject и т.п. И не забывай, что ты всё-таки на плюсах пишешь.

1 час назад, Antonshka сказал:

Это из Рихтера

спинлок это не sleep.

Ты чего-то всё время в кучу сваливаешь огромное количество вещей и топчешься в самых простых местах😀 Приколись лучше мыслью о том, сколько у тебя на это ресурсов ушло и чего по сравнению с этим стоит сохранение ресурсов машины(которая к тому же будет простаивать, а не выполнять другую работу).

Изменено пользователем youneuoy
Ссылка на комментарий
Поделиться на другие сайты

41 минуту назад, youneuoy сказал:

если очень хочешь, используй WaitForSingleObject, CreateWaitableTimer или любую другую вещь в качестве замены для sleep🙂И задержка для sleep как-то вроде настраивается(но не всеми системами поддерживается, и вообще это бесполезная для написания подобных библиотек инфа).

Sleep или замену Sleep я не планировал использовать. Это я просто привел цитату с сайта о том что поток не тратит CPU время при функции WaitForSingleObject.

Также и про спин, - речь не о самом спине, а о том что система умеет распределить процессорное время при заблокированном потоке, как я понял из всего прочитанного.

Вот пример более конкретный относительно объекта события и WaitForSinlgeObject. Из Рихтера.

Спойлер

If the resource is unavailable or the special event hasn't yet occurred, the system places the thread in a wait state, making
the thread unschedulable. This prevents the thread from wasting any CPU time. While your thread is waiting, the system
acts as an agent on your thread's behalf. The system remembers what your thread wants and automatically takes it out of
the wait state when the resource becomes available—the thread's execution is synchronized with the special event.

 

49 минут назад, youneuoy сказал:

Следует абстрагироваться от таких загонов, как абстрагирование, WaitForSingleObject и т.п. И не забывай, что ты всё-таки на плюсах пишешь.

Этот момент я не понял. Почему эти вещи загоны? Есть же принцип такой, Принцип единственной ответственности, что сущность должна заниматься исключительно своим делом. Вот и пускай объекты-контролы занимаются своими делами, а не основной поток.

WaitForSingleObject чем плох? Я пишу на плюсах, что значит не забывать? Твои сообщения я часто не понимаю, даже с нескольких раз, поэтому переспрашиваю. Дело во мне, потому что я замечаю это и при общении с другими.

 

53 минуты назад, youneuoy сказал:

Ты чего-то всё время в кучу сваливаешь огромное количество вещей и топчешься в самых простых местах😀

Да где же это простые вещи. На таких мелочах все и строится. Я пока возился с этим, да и вообще, с тем что раньше, многое чего узнал. А если бы не возился, то так бы и оставался с тем что было. Так что это к лучшему.

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Antonshka сказал:

Sleep или замену Sleep я не планировал использовать. Это я просто привел цитату с сайта о том что поток не тратит CPU время при функции WaitForSingleObject.

он и при слипе не тратит. Ты видел, на что ответ цитировал?

1 час назад, Antonshka сказал:

Вот и пускай объекты-контролы занимаются своими делами, а не основной поток.

основной поток - не объект, а принципы ООП не обязательны к выполнению.

1 час назад, Antonshka сказал:

Также и про спин, - речь не о самом спине, а о том что система умеет распределить процессорное время при заблокированном потоке, как я понял из всего прочитанного.

умеет. Видел в диспетчере задач "System Idle Process"? Вот там будет твой маленький вклад и выгоды из этого, что для программы, что для системы будет ровно 0.

1 час назад, Antonshka сказал:

Почему эти вещи загоны?

потому, что ты как минимум с понедельника этим загоняешься😀А мог бы сделать нужную штуку и забыть уже.

1 час назад, Antonshka сказал:

Я пишу на плюсах

но не используешь плюсовые штуки или их продвинутые альтернативы(их в различных библиотеках сделали очень много).

1 час назад, Antonshka сказал:

WaitForSingleObject чем плох?

тем, что задаче не соответствует и дополнительной доработки потребует. А задачу ты и не поставил конкретную, кстати. В плюсах есть над подобными штуками обёртки для всего, что тебе нужно - thread, atomic, cancellation_token, condition_variable, mutex, scoped_lock, не перечесть всего. Это всё удобнее, чем стандартные виндовые функции, при использовании этого тебе не придётся самостоятельно дописывать логику работы с тем же WaitForSingleObject для конкретной ситуации(а дописываешь ты её в каждом конкретном случае отдельно, не делая никаких обёрток, затрачивая время и усложняя код - 100% есть принцип ооп, "запрещающий" это). В том числе этими вещами можно заменить использование системы сообщений винды внутри приложения. Пара десятков строк кода и получишь штуку вида:

Спойлер
         while(работаем)
		{
			while (tasks.GetSize())
			{
				auto currTask = tasks.ExtractFromFront();

				switch (currTask.mapped()->task)
				{
				case TaskType::чё-то делать:
				{
					manager->чё-то делаем(currTask.mapped());
					break;
				}
				case TaskType::чё-то другое делать:
				{
					manager->чё-то другое делаем(currTask.mapped());
					break;
				}
				И так далее
				default:
					не работаем больше;
				}
				
			}

			manager->Чё-то обновляем();
			
			std::this_thread::sleep_for(спим);
		}

 

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

1 час назад, Antonshka сказал:

поэтому переспрашиваю

переспрашивать глупо, а спрашивать это ок. Глупый вопрос это тот, который не задан) Ты не переспрашиваешь, а уточняешь.

1 час назад, Antonshka сказал:

Да где же это простые вещи

место простое, задачу можно поставить простую и просто же её разрешить. А ты сам себе палки в колёса пихаешь.

Изменено пользователем youneuoy
  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

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