Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.56/70: Рейтинг темы: голосов - 70, средняя оценка - 4.56
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30

Вопрос по работе WaitForSingleObject

23.10.2010, 12:01. Показов 15292. Ответов 54
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Постановка задачи следующая. Есть основной процесс, который заведует отображением GUI и есть поток, который делает вычисления. Поток в процессе вычислений периодически должен отдавать результат главному процессу, чтобы тот отобразил результат на GUI. Т.е. схематично процесс работы выглядит так:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Поток */
...
  for ( ... )
  {
    /* Вычисления */
    ...
 
    /* 1. Записываем результат в глобальную переменную
     * 2. Запираем mutex, чтобы на следующей итерации цикла застрять
     *    на пункте 1, если главный процесс ещё не прочитал результат
     * 3. Посылаем сообщение о готовности результата главному процессу
     * 4. Продолжаем исполнение (переходим к следующей итерации цикла */
  }
...
C
1
2
3
4
5
6
7
8
/* Главный процесс */
 
/* Обработчик, в котором ловим сообщение от потока */
Handler ()
{
  /* 1. Отображаем результат на GUI
   * 2. Освобождаем mutex */
}
В этой схеме для запирания mutex'а (поток, пункт 2) я использовал WaitForSingleObject, а для освобождения mutex'а (главный процесс, пункт 2) - ReleaseMutex. Эта схема не работает.

Я предполагал, что WaitForSingleObject ожидает освобождения mutex'а, а потом запирает его. Предположение росло от того, что пока эту функцию я использовал только в тех случаях, когда mutex запирается и освобождается внутри одного и того же потока. В данном же случае имеем ситуацию, когда mutex запирается в одном потоке, а освобождается в другом. Для подтверждения неправомочности моего предположения достаточно написать исходник, в котором два раза подряд бы запускалось WaitForSingleObject. Если бы моё предположение было верно, то на втором запуске мы бы начали висеть, но этого не происходит.

Вопросы.
1. Просьба пояснить, что конкретно делает WaitForSingleObject. Без ссылок на MSDN и учебники, а своими словами. Чтобы было понятно, почему работает схема, когда mutex запирается и освобождается в одном и том же потоке, но не работает схема, когда это делается в разных потоках
2. Какими интерфейсами правильно осуществить желаемую схему работы
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
23.10.2010, 12:01
Ответы с готовыми решениями:

WaitForSingleObject - вопрос.
Привет. WinApi функция WaitForSingleObject. Как она работает? Ждет завершения патока (тот, что первий параметр), зачем тогда задержка...

Вопрос по работе с таблицей
Такой вот вопрос. Мне нужно поставить условие.. Если группа бюджетная, то итоговая сумма часов записывается в ячейку "Итог по...

Вопрос по работе с файлами
как в строке : open 'имя файла' for input as #1 сделать так чтобы программа искала файл в папке где находится прога повторюсь...

54
бжни
 Аватар для alex_x_x
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
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.10.2010, 00:02  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
Естественно работает, т.к. по сути логика такая: какой-то поток прочитал данные, разрешил работу только основному, и пока основной не сработает, ни один из потоков-писателей не может работать.
И какая тут многопоточность? Зачем вообще заводить основной поток, если всю работу с тем же успехом сделают сами писатели, помещая результат не в буфер, а посылая его напрямую куда надо. Долго выводить результат? Так ожидание от системы разрешения работать и потом вывод - еще дольше.
Наверное я плохо объясняю, попробую ещё раз. Многопоточность нужна ради того, чтобы GUI не подвисал в то время, как идёт прокачка данных из сети. Если, например, установление сетвевого соединения делать в главном потоке, то те 1-2 секунды, которые длится установление TCP-соединения, GUI не будет реагировать на внешние раздражители - окно нельзя двигать мышкой, нельзя нажимать на кнопки, оно не будет перерисовываться если поверх нашего окна двигать другие окна и т.п. Как я уже говорил, теоретически этого можно сделать и без потоков, но тогда придётся корячиться с неблокируемыми сокетами (или как там оно правильно называется) и всей портянкой, которая из этого вытекает. Т.е. несколько потоков - это не ради скорости и параллельности, а исключительно ради того, чтобы сделать программу удобной для пользования и заодно технически развязать логику работы узлов программы. Ну и одни лёгким движением руки превращать многопоточную программу в однопоточную (для удобства отладки, например)

Дополнительный геморрой - работа с графическими компонентами VCL должна осуществляться из главного потока. Ну вот так оно реализовано, что ж теперь поделать. В потоке должен работать лишь (сравнительно) "длительный" процесс скачивания данных из сети, а процесс прорисовки графических компонент как ни крути остаётся последовательным. Да, там они в своих TThread'ах придумали для этого Synchronize, но подобная реализация превращает программу в нечитабельную помойку и вынуждает постоянно цепляться за экземпляр класса TThread и тащить его во все дырки

Цитата Сообщение от kukuruku310 Посмотреть сообщение
Зачем там семафор, а тем более 2 - непонятно.
Этот вопрос я ставил и не раз. В качестве примера привёл linux'овый mutex (который требуется в количестве одна штука), но никто так и не рассказал об аналогичной конструкции под виндой (либо её там попросту и нет)

Цитата Сообщение от kukuruku310 Посмотреть сообщение
Вполне достаточно единственной и куда более легковесной критич.секции.

Ну хорошо, следуя примеру то ли 12, то ли 13, примерно так:

создание - InitializeCriticalSectionAndSpinCount

захват - EnterCriticalSection
освобождение - LeaveCriticalSection
удаление – DeleteCriticalSection

итого
main
InitializeCriticalSectionAndSpinCount
работа
DeleteCriticalSection

поток и главный поток
EnterCriticalSection
...
LeaveCriticalSection

проверял
Нет, не так. Надо чтобы операция "lock" происходила в одном потоке, а "release" - в другом. В посте #12 я написал, что критическая секция таким образом не работает. То, что ты нарисовал - это именно то, что есть во всех мануалах и учебниках для начинающих, когда каждый поток ставит блокировку на ресурс и сам же блокировку снимает
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
26.10.2010, 00:14
так как в линуксе не получится от того, что ни мьютекс, ни критеческая секция заблокировавший их поток не блокируют, они блокируют только другие потоки
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.10.2010, 00:24  [ТС]
Цитата Сообщение от alex_x_x Посмотреть сообщение
так как в линуксе не получится от того, что ни мьютекс, ни критеческая секция заблокировавший их поток не блокируют, они блокируют только другие потоки
Вот мне хочется понять, это такое принципиальное ограничение у винды? Если да, то получается, что можно обойтись минимум двумя объектами синхронизации. В то время как под линуксом можно было бы заблокировать mutex, записать результат, пнуть главный процесс, а после чего продолжать работу и не дожидаться, пока главный процесс откликнется. В крайнем случае мы повиснем на следующей выдаче результата.

Схема с двумя семафорами таким свойством не обладает. Но тем не менее потоки будут исполняться в параллель. Если процесс "рассчётов" является длительным по сравнению с процессом "обработки результата" (как это происходит в моём случае), то схема с двумя семафорами является работоспособной. В то время как kukuruku310, насколько я понимаю, пытается объяснить более общий вариант, правда я так нифига и не могу понять
0
бжни
 Аватар для alex_x_x
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
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.10.2010, 13:41  [ТС]
alex_x_x, это некая вариация примера с двумя семафорами, только вместо второго семафора используется мутекс. Ну и каждый мутекс запирается-освобождается внутри одного потока. Чем принципиально эта схема лучше? Тем, что используется более быстрый мутекс и меньше межпоточных заморочек (только один семафор), или есть ещё какие-то подводные камни?

И ещё. В главном потоке у тебя два вызова WaitForSingleObject. Что-то мне интуитивно кажется, что они в обратном порядке должны идти. Или нет?

Добавлено через 24 минуты
Или это некая неточная эмуляция линуксового варианта. Поток взводит семафор, главный процесс освобождает (аналог lock-release для мутекса в linux'е). Но поскольку lock работает не так (при повторном заходе не зависаем), то до кучи вокруг операций lock и release мы втыкаем внутрипотоковые мутексы, чтобы не зайти в нужную область и не выйти из нужной области раньше времени (т.е. чтобы с главным процессом всегда общался только один дочерний поток). В моём варианте поток отсылает сообщение о готовности главному процессу, а потому в главном процессе использование мутекса вроде бы как избыточное.

Что-то типа того?
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
26.10.2010, 17:52
Цитата Сообщение от Evg Посмотреть сообщение
И ещё. В главном потоке у тебя два вызова WaitForSingleObject. Что-то мне интуитивно кажется, что они в обратном порядке должны идти. Или нет?
если их переставить местами, то получим отличный дедлок, если у семафор будет занят
TCP будет висеть на мьютексе, а главный поток на семафоре
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.10.2010, 18:52  [ТС]
Ога, что-то я туплю
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
27.10.2010, 14:06
Я хотя и официально сосокочил из темы, но вот зудит одно место. Я НЕ ПОНИМАЮ!
Или я совсем ничерта не понимаю в синхронизации потоков, что, впрочем, как уже говорил, вполне вероятно, или я как-то уж очень по-своему понимаю многозадачность, или я вообще ничерта не понимаю...

1) зачем заставлять после КАЖДОГО срабатывания потока ждать отработки основного (вариант с семафорами), если реальная необходимость этого только при нехватке места в общем буфере
2) зачем использовать объекты ядра там, где без них вполне можно обойтись (семафор с мьютексом)
3) зачем использовать ядерный объект только для того, чтобы убедиться в наличии данных
4) почему непременно надо, чтобы захват был в одном потоке, освобождение-в другом, если речь идет о доступе к какому-то одному месту.

Короче, Evg, нарисовал вот еще варианты: первый - с Вашим любимым семафором, второй - без оного, третий - как пример использования второго на реальном чтении реальных файлов (если надумаете пробовать EXE , посмотрите сначала в CPP имя файла и размер). Все это дело, конечно надо было в SEH'и завернуть, но для примера...

Расскажите, в чем я не прав???
Вложения
Тип файла: zip Test.zip (77.0 Кб, 18 просмотров)
0
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
27.10.2010, 14:35
Цитата Сообщение от kukuruku310 Посмотреть сообщение
1) зачем заставлять после КАЖДОГО срабатывания потока ждать отработки основного (вариант с семафорами), если реальная необходимость этого только при нехватке места в общем буфере
буфер может быть например пустой, вы не думали об этом?
и не после каждого, а только когда там что-нибудь появится, это вам не ваши любимые спин-локи
Цитата Сообщение от kukuruku310 Посмотреть сообщение
2) зачем использовать объекты ядра там, где без них вполне можно обойтись (семафор с мьютексом)
то что вы постили до этого, это явно не то, чем стоит обходиться

Цитата Сообщение от kukuruku310 Посмотреть сообщение
3) зачем использовать ядерный объект только для того, чтобы убедиться в наличии данных
см выше
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
27.10.2010, 15:25  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
1) зачем заставлять после КАЖДОГО срабатывания потока ждать отработки основного (вариант с семафорами), если реальная необходимость этого только при нехватке места в общем буфере
В моём первом варианте я в потоке делал malloc и этот указатель отдавал главному процессу, где он его печатал на экран, а потом делал free. Тут вообще никакая синхронизация была не нужна, потому как нет пересекающихся данных (malloc всегда возвращает уникальный указатель). Но мне не нравится то, что вызов malloc'а делается в одном потоке, а освобождение памяти делается в другом - не красиво это. Второй момент - сейчас меня это не волнует, но может стрельнёт в будущем - без ожидания можем получить так, что потоки генерят данные слишком быстро и главный процесс просто не будет успевать их обработать и таким образом будет расти очередь необработанных сообщений.

Я уже объяснял, что скорость работы для меня не является критичной, потому как процесс печати (обработки) данных является "коротким" по сравнению с формированием данных (скачиванием из инета). И мне хочется технически простого решения, которое хорошо локализуется в рамках одного интерфейса

Цитата Сообщение от kukuruku310 Посмотреть сообщение
2) зачем использовать объекты ядра там, где без них вполне можно обойтись (семафор с мьютексом)
3) зачем использовать ядерный объект только для того, чтобы убедиться в наличии данных
Затем, что пока никто не показал другого рабочего решения

Цитата Сообщение от kukuruku310 Посмотреть сообщение
4) почему непременно надо, чтобы захват был в одном потоке, освобождение-в другом, если речь идет о доступе к какому-то одному месту.
А как ещё по другому?

Цитата Сообщение от kukuruku310 Посмотреть сообщение
Расскажите, в чем я не прав???
Если я осилю эти исходники, то может что-то и расскажу

Добавлено через 11 минут
Цитата Сообщение от kukuruku310 Посмотреть сообщение
Расскажите, в чем я не прав???
Например, в излишней сложности программы. Я не знаю, ради скорости делается или ради чего, но в такой программе очень просто закопаться

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

C
1
2
3
4
5
6
7
8
9
10
11
12
13
EnterCriticalSection
if (...)
{
  LeaveCriticalSection
  if (...)
  {
    EnterCriticalSection
    LeaveCriticalSection
  }
} else
{
  LeaveCriticalSection
}
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
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
27.10.2010, 21:45  [ТС]
Цитата Сообщение от kukuruku310 Посмотреть сообщение
так в Вашей ГУИ-шной программе
По-моему ты перепутал меня и alex_x_x, но это так, к слову

Цитата Сообщение от kukuruku310 Посмотреть сообщение
при этом теряется смысл содержания основного потока как такового – добавьте его код в код работы потоков – эффект будет тот же
Я уже несколько раз пояснял, а потому не хочется заходит на очередной круг. Ты мыслишь со слишком низкого уровня - с уровня winapi. А работаю на высоком уровне - на уровне библиотеки VCL. Если бы на уровне VCL было что-то вменяемое для работы с потоков - я бы до win api не стал спускаться, но, к сожалению, там либо этого дела нет, либо я не смог найти. Поэтому на вопросы "зачем разводить потоки там, где можно было бы обойтись без них" считай, что ответ звучит "так надо"

Цитата Сообщение от kukuruku310 Посмотреть сообщение
"почему непременно надо, чтобы захват был в одном потоке, освобождение-в другом, если речь идет о доступе к какому-то одному месту. А как ещё по другому?" По другому – это взял, если успел схватить, попользовался, освободил для других шустрых.
Ты опять мыслишь с низкого уровня. Тебе кажется эффективным работать с одни буффером и постоянно в него ДОписывать (а не пользоваться одним ресурсом, как это делаю я). Я не спорю, что это эффективно, но у меня такая задача не стоит. И я уже объяснял почему - время работы по скачиванию данных много больше времени их отображения, а потому мне совершенно некритично, что пользователь увидит данные на 50 миллисекунд позже, чем если бы всё делать "по науке"

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

Цитата Сообщение от kukuruku310 Посмотреть сообщение
И еще позволю себе совет: не заморачивайтесь Вы так на мелочах. В конце концов не так уж и принципиально важно с помощью чего будет выполнена синхронизация потоков. И если Вам ну никак не нравится моя схема, даже если просто необъяснимо не нарвится - так используйте ту, которая Вам больше по душе, более надежна на Ваш взгляд, более понятна и т.п. Потери от этого в конце концов не так уж и значительны. Заморочившись на не очень значительных вещах, вполне реально упустить что-то действительно важное. Для меня же эта тема представляет чисто теоретический интерес, т.к., повторяю, многопоточность (синхронзацию) применяю только ну в уж очень исключительных случаях.
Да я и не заморачиваюсь, я давно сделал по простому. А твои труды в любом случае даром не пропадут. Они полезны как тебе, так и мне. Просто я считаю, что ни один из твоих предложенных вариантов конкретно в данном случае мне не подходит. Но они могут подойти в других случаях а потому я их по любому сохраню. Я привык в линуксовым потокам, а потому мозги на виндузовые плохо переключаются

На текущий момент я выбрал для себя самое простое решение с двумя семафорами. Хотя правильнее было бы перейти на семафор+мутекс, но пока лениво по второму кругу тестировать кучу краевых случаев.

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

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// В конструкторе
...
#ifdef SUPPORT_THREAD
    m_Sem1 = CreateSemaphore (NULL, 1, 1, NULL);
    m_Sem2 = CreateSemaphore (NULL, 0, 1, NULL);
    m_MainProcThreadId = GetCurrentThreadId();
#endif // SUPPORT_THREAD
...
 
void __IN_TREAD__
TWindowDebug::AddString (const AnsiString &str)
{
#ifdef SUPPORT_THREAD
    if (GetCurrentThreadId() != m_MainProcThreadId)
    {
        // Метод вызван в потоке
        WaitForSingleObject (m_Sem1, INFINITE);
        m_DelayString = str;
        // Сообщение поймаем в WM_OnUserMessage
        PostMessage (Handle, WM_USER, 0, 0);
        ReleaseSemaphore (m_Sem2, 1, NULL);
    } else
#endif // SUPPORT_THREAD
    {
        // Метод вызван в основном процессе
        Memo->Lines->Add (str);
    }
}
 
#ifdef SUPPORT_THREAD
void __fastcall
TWindowDebug::WM_OnUserMessage (TMessage &msg)
{
    WaitForSingleObject (m_Sem2, INFINITE);
    AddString (m_DelayString);
    ReleaseSemaphore (m_Sem1, 1, NULL);
}
#endif // SUPPORT_THREAD
0
306 / 187 / 26
Регистрация: 14.02.2010
Сообщений: 547
27.10.2010, 23:53
Еще вдогонку...

Я там у себя в очередной раз сыдиотничал. При rewait'е старое значение будет потеряно. Чтобы обойти, наверное нужно дополнительно перед вызовом получения свежей порции данных убедиться, что данные потока (data[num]-так, кажется, сброшены).

А с единственным, неизменяемым буфером, я и корячился оттого, что, вроде как тема с этого и началась.

А так все понял, ухожу...
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
28.10.2010, 13:15  [ТС]
kukuruku310, если обратишь внимание на мой самый первый пост, то увидишь, что я сделал постановку задаи максимально абстрагированно от реальной задачи. И сделал я это не потому, что было лень расписывать что-то, а потому, что по опыту знаю, что в случае подробного описания я рискую вместо ответа на конкретный вопрос получить ответы на совсем другие вопросы. Конкретно мой вопрос сводился к "как пользоваться объектами синхронизации windows?". alex_x_x понял вопрос именно в той форме, в которой я его задал и ответил именно на тот вопрос, который я задал. Ты же пытаешься мне расписать алгоритм, как правильно работать с буффером, как сделать потоки, задаёшься вопросами типа "я не понимаю, почему надо делать так" и т.п. Ты мне всё время пытаешься дать ответ на вопрос, который я не задавал и ответ на который на данный момент меня совсем не интересует. Именно поэтому у тебя постоянно возникало желание уйти из темы. А я из твоих примеров попросту пытался вычленить именно то, что мне надо. Просто я уже начал догадываться, что требуемого мне свойства под виндой нет, но категоричного ответа никто не дал, а потому надеялся, что вдруг всё-таки что-то есть.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.10.2010, 13:15

Вопрос по работе со списками
foreach (var cache in cachelist) { if (cache.datetime < DateTime.Now.AddMinutes(-1)) { ...

Вопрос по работе со списками
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: justify <FONT size=3><FONT color=#000000><FONT face="Times New Roman Всем...

Вопрос по работе с TTimer
Прога работает примерно следующим образом. Раз в 5 секунд надо скачать инфу с web'а и обновить таблицу. Работаю через TTimer. Вроде бы всё...

Вопрос о работе с консолью
Здравствуйте. Мне нужно вводить начальные данные в консоль: количество + enter + через пробел цифры. Но проблема в том, что если я упущу...

Вопрос по лабораторной работе
program lab2; var x: array of real; k, n, i: integer; xx, eps, t: real; L: array of real; ff: text; begin assign (ff,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
55
Ответ Создать тему
Новые блоги и статьи
интеграция 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 мог продолжить работу без необходимости заново разбираться в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru