Синхронизация GUI приложение с потоком в DLL

Тема в разделе "WASM.BEGINNERS", создана пользователем KingT, 25 июн 2009.

  1. KingT

    KingT Member

    Публикаций:
    0
    Регистрация:
    12 янв 2006
    Сообщения:
    203
    Есть графическое приложение (окно).В определенный момент программа вызывает функцию из dll.Эта функция порождает поток и завершает работу.Поток делает свое дело и каким-то образом он должен увидомить основной поток(поток окна) о том что работа закончена.Как это реализовать лучше?
    Я думаю waitforsingleobject не прокатит ибо основной поток заснет и повесит систему(не будет работать меню и прочее).Мой вариант такой:поток при выполнении должен послать сообщение окну о завершенни и это сообщение обработает обработает оконная функция.Но поскольку поток не знает хэндля окна то этот хандл надо передать потоку при инициализации или через глобальную переменную.
    Это кривая реальзация или нет?
     
  2. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    имхо в данном случаи проше всего через PostThreadMessage.
     
  3. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    Наверное удобнее всего просто передать хендл окна в качестве параметра потоку.
     
  4. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Еще есть такая штука, как MsgWaitForMultipleObjects и в частности -- AtlWaitWithMessageLoop, который жрет quit message и поэтому крайне не рекомендован к употреблению)
     
  5. ohne

    ohne New Member

    Публикаций:
    0
    Регистрация:
    28 фев 2009
    Сообщения:
    431
    KingT

    гуй
    - создать ивент
    - передать функции хендл ивента,
    - создать таймер
    - по WM_TIMER чекать ивент
    поток в длл
    - при окончании исполнения пульсировать ивент
     
  6. KingT

    KingT Member

    Публикаций:
    0
    Регистрация:
    12 янв 2006
    Сообщения:
    203
    Попробывал сделать по той схеме что я описал.Оказалось что в VS6 и в VS8 MFC немного по разному маршрутизирует сообщения.В VS6 в классе CWinApp можно отлавливать сообщение прописав в карту ON_COMMAND(WM_USER,function)
    А в VS8 уже этого делать нельзя,сообщения конечно приходят главному потоку но чтоб отловить надо оверайдить функцию PreTranslateMessage.
     
  7. Z3N

    Z3N New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2009
    Сообщения:
    812
    Стоп! Ты меня сбил с мысли и я 5 минут ломал голову, как это сделать, а всё просто....
    Не надо никаких таймеров, просто когда будешь вызывать waitforsingleobject в поле сколько ждать надо поставить какое-нибудь значение.
    Если таймаут вышел, то ты возобновляешь поток и делаешь нужные дела, а потом опять waitforsingleobject с таймаутом. Надо будет, естественно, проверять, что тебе возвращает waitforsingleobject.
     
  8. KingT

    KingT Member

    Публикаций:
    0
    Регистрация:
    12 янв 2006
    Сообщения:
    203
    Так конечно можно сделать только когда я поставлю таймаут все равно waitforsingleobject повисит какое-то время(равное таймауту) и немного подвесит основной поток только зачем если есть механизм сообщений который гарантирует постоянную работу основного потока
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Зачем сообщения если есть пара событий(Event Pair).
     
  10. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    ну можно воткнуть waitforsingleobject с таймером 0, только куда? в обработчик сообшение не стоит, так как нет гарантии что придут какие либо сообщения для этого окна. таймер делать - это ваше ламочушь.
     
  11. SWR

    SWR New Member

    Публикаций:
    0
    Регистрация:
    11 май 2006
    Сообщения:
    226
    Адрес:
    Russia
    А че через глобальную булевую переменную незя?
    И быстро, че заморачиваться синхронизациейи через waitforsingleobject, если нет каллизий по ресурсам.
     
  12. SWR

    SWR New Member

    Публикаций:
    0
    Регистрация:
    11 май 2006
    Сообщения:
    226
    Адрес:
    Russia
    //в обработчик сообшение не стоит, так как нет гарантии что придут какие либо сообщения для этого окна. таймер делать - это ваше ламочушь.
    Так самому из треда послать сообщений таймера несудьба?
     
  13. ohne

    ohne New Member

    Публикаций:
    0
    Регистрация:
    28 фев 2009
    Сообщения:
    431
    создать такую проблему из ничего вот это точно чушь
     
  14. Z3N

    Z3N New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2009
    Сообщения:
    812
    Кажется я нашёл ответ на твой вопрос, может, конечно, он немного запоздал, но лучше поздно чем никогда....
    Всё довольно легко, ответ на твой вопрос находился в Рихтере :О.... Недавно решил почитать одну из его книг про винду и нашёл весьма интересную главу. Чтобы ты смог сам насладиться чтением, я прикрепил всю главу, но, если честно, то тебя интересует лишь файл ch11d.htm. Кстати, 10 опера его почему-то неправильно отображает. То, что там написано должно тебя устроить, ведь твой тред не заморозиться и сможет делать свою очень важную работу. Если кому интересно, но лень качать архив, скажу, что нужная функция называется RegisterWaitForSingleObject.
    Рихтер, конечно, молодчина, он описывает такие функции, что ни на фасме написать, ни в мсдн-эне описать :). Читаешь... и сразу чувствуешь что умнеешь ~%). Всё, больше не буду тратить время на писание, лучше прочитаю ещё пару глав перед сном (а текст я пишу в 0:25, вы не смотрите когда пост запостен...).
     
  15. icent

    icent New Member

    Публикаций:
    0
    Регистрация:
    23 апр 2009
    Сообщения:
    154
    Только на русском..:


    Код (Text):
    1. Сценарий 3: вызов функций при освобождении отдельных объектов ядра
    2.  
    3. Microsoft обнаружила, что во многих приложениях потоки порождаются только для того, чтобы ждать на тех или иных объектах ядра. Как только объект освобождается, поток посылает уведомление и снова переходит к ожиданию того же объекта. Неко торые разработчики умудряются писать программы так, что в них создается несколь ко потоков, ждущих один объект. Это невероятное расточительство системных ресур сов Конечно, издержки от создания потоков существенно меньше, чем от создания процессов, но и потоки не воздухом питаются У каждого из них свой стек, не говоря уж об огромном количестве команд, выполняемых процессором при создании и унич тожении потока Поэтому надо стараться сводить любые издержки к минимуму.
    4.  
    5. Если Вы хотитe зарегистрировать рабочий элемент так, чтобы он обрабатывался при освобождении какого-либо объекта ядра, используйте еще одну новую функцию пула потоков
    6.  
    7. BOOL RegisterWaitForSingleOb]ect( PHANOLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK pfnCallback, PVOIO pvContext, ULONG dwMilliseconrts, ULONG dwFlags);
    8.  
    9. Эта функция передает Ваши параметры компоненту поддержки ожидания в пуле , потоков. Вы сообщаете ему, что рабочий элемент надо поставить в очередь, как толь
    10.  
    11. ко освободится объект ядра (на который указывает bObject) Кроме того, Вы можете задать ограничение по времени, т. e. элемент будет помещен в очередь через опреде ленное время, даже если объект ядра так и нс освободится (При этом допустимы значения INFINITE и 0.) В общем, эта функция похожа на хорошо известную функ цию WattForSingIeObject (см. главу 9). Зарегистрировав рабочий элемент на ожидание указанного объекта, RegisterWaitForStngleObject возвращает в параметре phNewWait Object описатель, идентифицирующий объект ожидания
    12.  
    13. Данный компонент реализует ожидание зарегистрированных объектов через Wait ForMultipleObjects и поэтому накладывает те же ограничения, что и эта функция Одно из них заключается в том, что нельзя ожидать тот жс объект несколько paз. Так что придется вызывать DuplicateHandle и отдельно регистрировать исходный и продуб лированный описатель Вам должно быть известно, что единовременно функция WaitForMultipleObjects способна отслеживать не болсе 64 (MAXIMUM_WAIT_OBJECTS) объектов А что будет, если попробовить зарегистрировать с ее помощью более 64 объектов? Компонент поддержки ожидания создаст еще один поток, который тоже вы зовет WaitForMultipleObjects. (На самом деле новый поток создается на каждые 63 объек та, потому что потокам приходится использовать объект ядра «ожидаемый таймер", контролирующий таймауты)
    14.  
    15. По умолчанию рабочий элемент, готовый к обработке, помещается в очередь к потокам компонента поддержки других операций (не связанных с вводом-выводом). В конечном счете один из его потоков пробудится и вызовет Вашу функцию, у кото рой должен быть следующий прототип.
    16.  
    17. VOID WINAPI WaitOrTimerCallbackFunc( PVOID pvContext, BOOLEAN fTimerOrWaitFired);
    18.  
    19. Параметр pfTimerOrWaitFired принимает значение TRUE, если время ожидания ис текло, или FALSE, если объект освободился раньше.
    20.  
    21. В параметре dwFlags функции RegisterWaitForSingleObject можно передать флаг WT_EXECUTEINWAITTHREAD, который заставляет выполнить функцию рабочего эле мента в одном из потоков компонента поддержки ожидания. Это эффективнее, пото му что тогда рабочий элемент не придется ставить в очередь компонента поддержки других операций. Но в то же время и опаснее, так как этот поток не сможет ждать освобождения других объектов. Используйте этот флаг, только если Ваша функция выполняется быстро
    22.  
    23. Вы можете также передать флаг WT_EXECUTEINIOTHREAD, если Ваш рабочий эле мент выдаст запрос на асинхронный ввод-вывод, или WT_EXECUTEINPERSISTENT THREAD, если ему понадобится операция с использованием постоянно существующе го потока. В случае длительного выполнения функции рабочего элемента можно при менить флаг WT_EXECUTELONGFUNCTION Указывайте этот флаг, только если рабо чий элемент передается компоненту поддержки ввода-вывода или других операций, — функцию, требующую продолжительной обработки, нельзя выполнять в потоке, ко торый относится к компоненту поддержки ожидания.
    24.  
    25. И последний флаг, о котором Вы должны знать, — WT_EXECUTEONLYONCE. До пустим, Вы зарегистрировались на ожидание объекта ядра "процесс" После перехо да в свободное состояние он так и останется в этом состоянии, что заставит компо нент поддержки ожидания постоянно включать в очередь рабочие элементы. Так вот, чтобы избежать этого, Вы можете использовать флаг WT_EXECUTEONLYONCE — он сообщает пулу потоков прекратить ожидание объекта после первой обработки рабо чего элемента.
    26.  
    27. Теперь представьте, что Вы ждете объект ядра "событие с автосбросом": сразу после освобождения он тут же возвращается в занятое состояние; при этом в очередь ста вится соответствующий рабочий элемент. На этом этапе пул продолжает отслеживать объект и снова ждет его освобождения или того момента, когда истечет время, выде ленное на ожидание. Если состояние объекта Вас больше не интересует, Вы должны снять его с регистрации. Это необходимо даже для отработавших объектов, зарегис трированных с флагом WT_EXECUTEONLYONCE. Вот как выглядит требуемая для этого функция:
    28.  
    29. BOOL UnregisterWaitEx( HANOLE hWaitHandle, HANDLE hCompletionEvent);
    30.  
    31. Первый параметр указывает на объект ожидания (его описатель возвращается RegisterWaitForSingleObject), а второй определяет, каким образом Вас следует уведом лять о выполнении последнего элемента в очереди. Как и в DeleteTimerQueueTimer, Вы можете передать в этом параметре NULL (если уведомление Вас не интересует), INVA LID_HANULEVALUF, (функция блокируется до завершения обработки всех элементов в очереди) или описатель объекта-события (переходящего в свободное состояние при завершении обработки очередного элемента). В ответ на неблокирующий вызов Unre gisterWaitEx возвращает TRUE, если очередь пуста, и FALSE в ином случае (при этом GetLastError возвращает STATUS_PENDING).
    32.  
    33. И вновь будьте осторожны, передавая значение INVALIDHANDLE_VALUE. Функция рабочего элемента заблокирует сама себя, если попытается снять с регистрации выз вавший cc объект ожидания. Такая попытка подобна команде: приостановить меня, пока я не закончу выполнение, — полный тупик. Но UnregisterWaitEx разработана так, чтобы предотвращать тупиковые ситуации, когда поток компонента поддержки ожи дания выполняет рабочий элемент, а тот пытается снять с регистрации запустивший его объект ожидания. И еще один момент: не закрывайте описатель объекта ядра до тех пор, пока не снимете его с регистрации. Иначе недействительный описатель по падет в WaitForMultipleObjects, к которой обращается поток компонента поддержки ожидания. Функция моментально завершится с ошибкой, и этот компонент переста нет корректно работать.
    34.  
    35. И последнее- никогда не вызывайте PulseEvent для освобождения объекта-события, зарегистрированного на ожидание. Поток компонента поддержки ожидания скорее всего будет чем-то занят и пропустит этот импульс от PulseEvent. Но эта проблема для Вас не нова — PulseEvent создает ее почти во всех архитектурах поддержки потоков