|
|
|||||||||||
Вопрос по работе WaitForSingleObject23.10.2010, 12:01. Показов 15292. Ответов 54
Метки нет (Все метки)
Постановка задачи следующая. Есть основной процесс, который заведует отображением GUI и есть поток, который делает вычисления. Поток в процессе вычислений периодически должен отдавать результат главному процессу, чтобы тот отобразил результат на GUI. Т.е. схематично процесс работы выглядит так:
Я предполагал, что WaitForSingleObject ожидает освобождения mutex'а, а потом запирает его. Предположение росло от того, что пока эту функцию я использовал только в тех случаях, когда mutex запирается и освобождается внутри одного и того же потока. В данном же случае имеем ситуацию, когда mutex запирается в одном потоке, а освобождается в другом. Для подтверждения неправомочности моего предположения достаточно написать исходник, в котором два раза подряд бы запускалось WaitForSingleObject. Если бы моё предположение было верно, то на втором запуске мы бы начали висеть, но этого не происходит. Вопросы. 1. Просьба пояснить, что конкретно делает WaitForSingleObject. Без ссылок на MSDN и учебники, а своими словами. Чтобы было понятно, почему работает схема, когда mutex запирается и освобождается в одном и том же потоке, но не работает схема, когда это делается в разных потоках 2. Какими интерфейсами правильно осуществить желаемую схему работы
0
|
|||||||||||
| 23.10.2010, 12:01 | |
|
Ответы с готовыми решениями:
54
Вопрос по работе с файлами |
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
|
| 25.10.2010, 23:26 | |
|
kukuruku310, критическая секция не учитывает, что можно читать, когда ничего не записано, а так да
ну и семафоры более интеллектуальный доступ обеспечиваю Добавлено через 17 минут по-поводу WaitForSingleObject Функция на все времена, вместо того, чтобы сделать разные функции для разных объектов синхронизации - надо использовать одну, хорошо это или плохо общее поведение функции - дожидается определенного события или возвращает ошибку для мьютекса: если мьютекс занят - ожидает освобождения, при освобождении - продолжает выполнение и блокирует мьютекс исключение для потока, вызвавшего WaitForSingleObject для мьютекса, который был прежде заблокирован этим же потоком - поток продолжит выполнение, но у мьютекса увеличится счетчик рекурсии (для освобождения мьютекса потребуется несколько раз потоком вызвать ReleaseMutex ) Захвативший мьютекс поток освобождает его вызовом ReleaseMutex (или понижает счетчик рекурсии) для семафора: если значение семафора 0 - ожидает увеличения значения до != 0, как только это случается - понижает его значение (блокирует) и начинает выполнение ReleaseSemaphore - соответственно увеличивает значение для потоков, процессов: WaitForSingleObject ожидает завершение потоков, процессов и продолжает выполнение потока для событий: WaitForSingleObject ожидает установки события в TRUE, как только это произошло - продолжает выполнение (в зависимости от типа события может сбрасывать его в FALSE) как-то так, по-памяти
0
|
|
|
|
||||
| 26.10.2010, 00:02 [ТС] | ||||
|
Дополнительный геморрой - работа с графическими компонентами VCL должна осуществляться из главного потока. Ну вот так оно реализовано, что ж теперь поделать. В потоке должен работать лишь (сравнительно) "длительный" процесс скачивания данных из сети, а процесс прорисовки графических компонент как ни крути остаётся последовательным. Да, там они в своих TThread'ах придумали для этого Synchronize, но подобная реализация превращает программу в нечитабельную помойку и вынуждает постоянно цепляться за экземпляр класса TThread и тащить его во все дырки
0
|
||||
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
|
| 26.10.2010, 00:14 | |
|
так как в линуксе не получится от того, что ни мьютекс, ни критеческая секция заблокировавший их поток не блокируют, они блокируют только другие потоки
0
|
|
|
|
||
| 26.10.2010, 00:24 [ТС] | ||
|
Схема с двумя семафорами таким свойством не обладает. Но тем не менее потоки будут исполняться в параллель. Если процесс "рассчётов" является длительным по сравнению с процессом "обработки результата" (как это происходит в моём случае), то схема с двумя семафорами является работоспособной. В то время как kukuruku310, насколько я понимаю, пытается объяснить более общий вариант, правда я так нифига и не могу понять
0
|
||
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
|
| 26.10.2010, 01:05 | |
|
насколько я понимаю, это так разрешается
если ТСP поток складирует данные, те там некоторый буффер с значениями //в главном потоке hM = CreateMutex( 0, FALSE, 0 ); //критическая секция hS = CreateSemaphore( 0, 0, INFINITE, 0 ); //семафор для главного потока CreateThread( ... ) //создаем TCP //TCP WaitForSingleObject( hM, INFINITE ); //.. ReleaseSemaphore( hS, 1, 0 ); ReleaseMutex( hM ); //главный поток WaitForSingleObject( hS, INFINITE ); WaitForSingleObject( hM, INFINITE ); //.. ReleaseMutex( hM ); Добавлено через 7 минут если TCP хранит постоянно только одну копию данных, то hS = CreateSemaphore( 0, 0, 1, 0 );
0
|
|
|
|
|
| 26.10.2010, 13:41 [ТС] | |
|
alex_x_x, это некая вариация примера с двумя семафорами, только вместо второго семафора используется мутекс. Ну и каждый мутекс запирается-освобождается внутри одного потока. Чем принципиально эта схема лучше? Тем, что используется более быстрый мутекс и меньше межпоточных заморочек (только один семафор), или есть ещё какие-то подводные камни?
И ещё. В главном потоке у тебя два вызова WaitForSingleObject. Что-то мне интуитивно кажется, что они в обратном порядке должны идти. Или нет? Добавлено через 24 минуты Или это некая неточная эмуляция линуксового варианта. Поток взводит семафор, главный процесс освобождает (аналог lock-release для мутекса в linux'е). Но поскольку lock работает не так (при повторном заходе не зависаем), то до кучи вокруг операций lock и release мы втыкаем внутрипотоковые мутексы, чтобы не зайти в нужную область и не выйти из нужной области раньше времени (т.е. чтобы с главным процессом всегда общался только один дочерний поток). В моём варианте поток отсылает сообщение о готовности главному процессу, а потому в главном процессе использование мутекса вроде бы как избыточное. Что-то типа того?
0
|
|
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
||
| 26.10.2010, 17:52 | ||
|
TCP будет висеть на мьютексе, а главный поток на семафоре
0
|
||
|
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
|
|
| 27.10.2010, 14:06 | |
|
Я хотя и официально сосокочил из темы, но вот зудит одно место. Я НЕ ПОНИМАЮ!
Или я совсем ничерта не понимаю в синхронизации потоков, что, впрочем, как уже говорил, вполне вероятно, или я как-то уж очень по-своему понимаю многозадачность, или я вообще ничерта не понимаю... 1) зачем заставлять после КАЖДОГО срабатывания потока ждать отработки основного (вариант с семафорами), если реальная необходимость этого только при нехватке места в общем буфере 2) зачем использовать объекты ядра там, где без них вполне можно обойтись (семафор с мьютексом) 3) зачем использовать ядерный объект только для того, чтобы убедиться в наличии данных 4) почему непременно надо, чтобы захват был в одном потоке, освобождение-в другом, если речь идет о доступе к какому-то одному месту. Короче, Evg, нарисовал вот еще варианты: первый - с Вашим любимым семафором, второй - без оного, третий - как пример использования второго на реальном чтении реальных файлов (если надумаете пробовать EXE , посмотрите сначала в CPP имя файла и размер). Все это дело, конечно надо было в SEH'и завернуть, но для примера... Расскажите, в чем я не прав???
0
|
|
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
||||
| 27.10.2010, 14:35 | ||||
|
и не после каждого, а только когда там что-нибудь появится, это вам не ваши любимые спин-локи
0
|
||||
|
|
|||||||||||
| 27.10.2010, 15:25 [ТС] | |||||||||||
|
Я уже объяснял, что скорость работы для меня не является критичной, потому как процесс печати (обработки) данных является "коротким" по сравнению с формированием данных (скачиванием из инета). И мне хочется технически простого решения, которое хорошо локализуется в рамках одного интерфейса Добавлено через 11 минут Пока я не расписал точки входа и выхода в виде коротенького блока, у меня просто мозги заклинивало, где там начало и где конец
0
|
|||||||||||
|
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
|
|
| 27.10.2010, 18:28 | |
|
Ну тогда еще раз.
"Буфер может быть пустой" – это проверяется простой проверкой текущего индекса этого буфера, доступ к которому все равно идет вместе с доступом к самому буферу внутри критической секции. "не после каждого, а только когда там что-нибудь появится" – я бы это перефразировал в "после каждого появления данных в буфере" и добавил – закрывая вход всем остальным потокам, хотя в данный момент в этом может и не быть острой необходимости. т.е. работа идет по схеме "сработал поток-жди работы главного", при этом теряется смысл содержания основного потока как такового – добавьте его код в код работы потоков – эффект будет тот же. Не нравится Вам, что основной поток без надобности захватывает ресурс – так в Вашей ГУИ-шной программе это реализуется простой посылкой сообщения, только в ответ на которую поток и начинает свои захватнические действия. "это вам не ваши любимые спин-локи" – тут я на все 100 процентов согласен. Оттого, что я их, скорее всего, неправильно использовал. В идиотстве я себе никогда не отказывал. "зачем использовать объекты ядра там, где без них вполне можно обойтись (семафор с мьютексом)". Но ведь можно же, т.к. критическая секция-не есть объект ядра. Второй момент - … без ожидания можем получить так, что потоки генерят данные слишком быстро и главный процесс просто не будет успевать их обработать" – в моем примере потоки в самом начале проверяют, смогут ли они в данный момент записать свои данные в буфер, и только после этого начинают непосредственную деятельность. Правда, в качестве неприятного побочного эффекта, приходится делать перезахват блокировщика, но издержки этого, по-моему, гораздо меньше, чем вызов Wait… Если прогоните Exe из примера 2 или 3, то в последней колонке полученного log-файла можно увидеть сколько раз поток ждал освобождения буфера. А в реальности этого скорее всего вообще не будет, т.к. даже при очень маленьком буфере это происходит достаточно нечасто, учитывая время обработки данных. рабочее решение – пример 3. Утрировано, но реально. "почему непременно надо, чтобы захват был в одном потоке, освобождение-в другом, если речь идет о доступе к какому-то одному месту. А как ещё по другому?" По другому – это взял, если успел схватить, попользовался, освободил для других шустрых. Ну а по поводу сложности – так не считаю какой-то суперсложной функу из 40 строчек, учитывая, что все блочные скобки расположены на отдельной строке, а их там аж 15 штук - в итоге остается 25 реального кода, а если еще откинуть отладочные сообщения.... Добавлено через 10 минут Просто чужой код, естественно, воспринимается не так быстро, как собственный, особенно, если там другой стиль форматирования. Перепишите на свой лад - и, думаю, сразу все станет на свои места. Добавлено через 25 минут И еще позволю себе совет: не заморачивайтесь Вы так на мелочах. В конце концов не так уж и принципиально важно с помощью чего будет выполнена синхронизация потоков. И если Вам ну никак не нравится моя схема, даже если просто необъяснимо не нарвится - так используйте ту, которая Вам больше по душе, более надежна на Ваш взгляд, более понятна и т.п. Потери от этого в конце концов не так уж и значительны. Заморочившись на не очень значительных вещах, вполне реально упустить что-то действительно важное. Для меня же эта тема представляет чисто теоретический интерес, т.к., повторяю, многопоточность (синхронзацию) применяю только ну в уж очень исключительных случаях.
0
|
|
|
|
|||||||||||
| 27.10.2010, 21:45 [ТС] | |||||||||||
![]() На текущий момент я выбрал для себя самое простое решение с двумя семафорами. Хотя правильнее было бы перейти на семафор+мутекс, но пока лениво по второму кругу тестировать кучу краевых случаев. Схематично у меня примерно так:
0
|
|||||||||||
|
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
|
|
| 27.10.2010, 23:53 | |
|
Еще вдогонку...
Я там у себя в очередной раз сыдиотничал. При rewait'е старое значение будет потеряно. Чтобы обойти, наверное нужно дополнительно перед вызовом получения свежей порции данных убедиться, что данные потока (data[num]-так, кажется, сброшены). А с единственным, неизменяемым буфером, я и корячился оттого, что, вроде как тема с этого и началась. А так все понял, ухожу...
0
|
|
|
|
|
| 28.10.2010, 13:15 [ТС] | |
|
kukuruku310, если обратишь внимание на мой самый первый пост, то увидишь, что я сделал постановку задаи максимально абстрагированно от реальной задачи. И сделал я это не потому, что было лень расписывать что-то, а потому, что по опыту знаю, что в случае подробного описания я рискую вместо ответа на конкретный вопрос получить ответы на совсем другие вопросы. Конкретно мой вопрос сводился к "как пользоваться объектами синхронизации windows?". alex_x_x понял вопрос именно в той форме, в которой я его задал и ответил именно на тот вопрос, который я задал. Ты же пытаешься мне расписать алгоритм, как правильно работать с буффером, как сделать потоки, задаёшься вопросами типа "я не понимаю, почему надо делать так" и т.п. Ты мне всё время пытаешься дать ответ на вопрос, который я не задавал и ответ на который на данный момент меня совсем не интересует. Именно поэтому у тебя постоянно возникало желание уйти из темы. А я из твоих примеров попросту пытался вычленить именно то, что мне надо. Просто я уже начал догадываться, что требуемого мне свойства под виндой нет, но категоричного ответа никто не дал, а потому надеялся, что вдруг всё-таки что-то есть.
0
|
|
| 28.10.2010, 13:15 | |
|
Вопрос по работе со списками Вопрос по работе со списками Вопрос по работе с TTimer Вопрос о работе с консолью Вопрос по лабораторной работе Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS
Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
|
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи.
Через несколько переработок от PHP кода к C89 (надеюсь, 89).
Но довольно запутанно получилось. Код для Linux.
Но если убрать time и то, что с ним. . .
|
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки
Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
|
rest api anylogic - выполнение модели на своём русском сайте
anaschu 02.07.2026
Как подружиться с AnyLogic Cloud API, победить провайдеров и развернуться Java-бэкенд в Docker на бесплатном хостинге: Двухдневный лог борьбы
Всем привет! Хочу поделиться свежим (и довольно. . .
|
|
Где деньги лежат
kumehtar 02.07.2026
Это - японская подводная лодка I-52 (тип C2, кодовое имя Momi) вышла из Японии в марте 1944 года с миссией в оккупированную немцами Францию (Лорьян). Это была одна из «Янаги»-миссий по обмену. . .
|
Krabik для WoW 3.3.5a, многоязычный
AmbA 02.07.2026
Допилил бота, думаю что окончательно. Изменения:
- добавлена многоязычность
- добавлено снятие скриншотов
- добавлено поддержание бафов хождения по воде (для жреца, дк и шамана)
- и так, по. . .
|
Алиса нашла кучу ошибок компиляции и запуска в проекте, который без проблем компилировался и запускался)))
anaschu 30.06.2026
Я пока посмеюся, но завтра проверю. А вообще интерсно. Дал алисе файл, в котором точно нет ошибок компиляции и запуска, и попросил их найти. Нашла кучу)))
Критические ошибки, мешающие компиляции и. . .
|
сукцессия 16. Общий обзор, в основном что бы другие ии поняли
anaschu 29.06.2026
# Передаточный документ: модель микоризной сукцессии (для нового чата)
Этот документ предназначен для того, чтобы новый чат Claude мог продолжить
работу без необходимости заново разбираться в. . .
|