![]() |
|
Модераторы: feodorv, GremlinProg, xvr, Fixin |
![]()
|
|
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Всем доброго дня.
Задача стоит раз в секунду одним потоком выделить область для данных, вторым заполнить, третим отобразить. Период в секунду нужно отобразить скорее всего ожидаемым таймером. Делаю вот так:
В результате таблица один раз отрисовывается и все, хотя третий параметр функции SetWaitableTimer(...,...,1000,...,...,...) равен насколько я понимаю одной секунде. т.е. после первой отрисовки J = 99 и следующая должна начаться с этого значения. Что делаю не так? блин код как-то не так отображаться стал, поэтому нужную строку подсветил Это сообщение отредактировал(а) GremlinProg - 15.3.2012, 07:13 |
|||
|
||||
| Dem_max |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1780 Регистрация: 12.4.2007 Репутация: 16 Всего: 39 |
-------------------- Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte") |
|||
|
||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
а вот так можно устанавливать время постоянного срабатывания с интервалом 1 сек:
или обязательно создавать переменную системного времени и приводить их к FILETIME а потом уже использовать???? Думаю что нет.. Разве что если нам надо что бы таймер сработал в определенное время, тогда да. А в данном случае мой таймер освобождается для потоков через 10 сек после создания и так через 1 сек в дальнейшем должно быть, но не получается Это сообщение отредактировал(а) wallstreet - 11.3.2012, 21:08 |
|||
|
||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
В коде этого нет. Потоки Thread1, Thread2 и Thread3 отработают один раз и завершатся. Потом. По смыслу задачи, сначала отрабатывает первый поток с выделением памяти, уже потом должен отрабатывать второй поток с инициализацией, а, гм, третий (но есть ещё один наш, изначальный поток) должен заняться отрисовкой (в реальности он лишь посылает сообщение в оконную процедуру). Схема взаимодействия потоков в приведённом коде ужасная((( Её необходимо переделать. Поскольку для отрисовки (в любой момент времени!) данных эти самые данные необходимо иметь, то, действительно, эти данные необходимо защитить от одновременного доступа. Критическая секция здесь подойдёт лучше всего, но не просто потому, что проще всего, а потому, что не имеет принадлежности к потоку, вызвавшему EnterCriticalSection (то есть освободить секцию мы можем в любом другом потоке!). Именно этим свойством я и предлагаю воспользоваться. Но ещё раз скажу, что задача осложняется тем, что:
Таким образом получается: Первый поток Цикл по:
Цикл по:
Цикл по:
Однако даже в таком варианте схема имеет изъян. Он связан с тем, что за время между срабатываниями таймера второй поток может не успеть проинициализировать данные, и при следующем срабатывании таймера первый поток начнёт перезаказывать память, а второй будет всё ещё инициализировать выделенную в прошлый раз память. Такая ситуация лечится тем, что придётся ввести вторую критическую секцию, которой обычным образом дополнительно защищаются данные в первом и втором потоках, ну с этим Вы справитесь самостоятельно... ЗЫ События 1, 2 и 3 также используются для корректного завершения приложения. Это сообщение отредактировал(а) feodorv - 11.3.2012, 23:17 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| wallstreet |
|
||||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Огромное спасибо всем за участие.
Надо сделать. В этом собственно и загвоздка. Из определения: ОЖИДАЕМЫЕ ТАЙМЕРЫ - объекты ядра, которые самосоятельно переходят в свободное состояние в определенное время или через регулярные промежутки времени. Вот мне этот промежуток и не удается задать(( Ну а теперь по порядку.
А кто событие для первого потока будет освобождать? Предполагаю что поток 3й или раздел отрисовки окна WM_PAINT?
Насколько я понял, чо проверять должны на выполнение условия, т.е. применительно к потоку1, память под массив выделена, значит освобождаем событие1 переходим во второй поток который завершает первый или как? Вот что получилось:
Вообщем, так, к слову, в задаче нужно было обойтись исключительно критическими секциями. Но для меня важно уметь использовать все средства взаимодействия, поэтому благодарю за саппорт в обучении и надеюсь поможете разобраться с таймером его периодичностью и другими вопросами. Это сообщение отредактировал(а) wallstreet - 12.3.2012, 18:32 |
||||||||
|
|||||||||
| feodorv |
|
||||||||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Было бы проще, если бы в доступности находился весь проект)))
Несколько замечаний: 1/
Если мы создаём события со сбросом вручную, то
Правда, тогда нужны соответствующие ResetEvent в нужных местах... 2/ Всё-таки мы сначала ждём таймера, а уже потом захватываем cs1... Этим мы даём возможность окну отрисовать клиенскую область при разных событиях (схлопывание-раскрытие окна, перекрытие окна, завершение работы...):
Ну и устанавливать события можно вне сферы деятельности критической секции... 3/ Имелось ввиду, что если потоки будут бесперерывно работать, то их нужно корректно завершить при завершении всего приложения (при IDM_EXIT). Обычно это делается так: заводится глобальная булева переменная (назовём её done), которая принимает значение TRUE только при необходимости завершить работу, а все созданные потоки пробуждаются тем или иным способом. Но поскольку Thread1 висит исключительно на таймере, то для завершения потока нужно дожидаться срабатываения таймера (для 1 секунды это терпимо, а если нужно было раз в минуту?) Для этого и вводилось соответствующее событие в Thread1, которое сбрасывалось бы только при IDM_EXIT. 4/ Вот это отсутствует
Иными словами, нужно так:
Аналогично и в других потоках!!! 4/ Завершение приложения - отдельная песня. Ибо необходимо дождаться завершения всех трёх потоков через WaitForMultipleObjects, предварительно установив done в TRUE и пробудив потоки через SetEvent. Ждать можно максимум 10 секунд...
И уже потом DestroyWindow()... 5/ при отрисовке нужно учитывать, что buf может быть NULL (например, если отрисовка произойдёт быстрее, чем первый поток успеет захватить критическую секцию), тогда просто можно ничего не рисовать. Гм, нужно также проследить, что Вы очищаете клиенскую область окна при перерисовке... Мы будем ждать или-или (а не и-и), поэтому если сработает таймер, то и поток1 пробудится. Про событие и его роль уже написал Во-первых, потоки отрабытывают всего один раз, сколько бы раз там таймер не срабатывал... Во-вторых, зачем эта задержка:
Почему не просто 0? А так, на вид, всё правильно))) В сущности, можно было бы начать писать программу с одного потока, сидящего на таймере, а два других добавить позже, когда таймер заработает...
Ну, эээ, теоретически, можно всё переписать исключительно через критические секции, но это будет сильно напряжно))) Так что потихоньку двигаемся к финишу))) Это сообщение отредактировал(а) feodorv - 12.3.2012, 23:48 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||||||||||||
|
|||||||||||||||||
| wallstreet |
|
||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Ну вроде подогнал под ваши рекомендации.
По пунктам: 1\ А зачем нам создавать события с ручным сбросом. Мы дождались освобождения события и оно автоматом занимается потоком дождавшимся. Т.о. мы создаем событие занятым изначально, потом первый поток его освобождает для второго, а второй дождавшись занимает ну и тд. 2\ реализовал по примеру 4\ 3\ реализовал в IDM_EXIT после чего при попытке выхода путем Menu\Exit прога висит секунд 5, потом закрывает окно. Однако для меня немного непонятным остается, что значит:
4\ В целом не понимаю зачем завершать поток при выходе? Он ведь в рамках процесса окна создается, насколько я понимаю, соответственно и завершится по завершению процесса окна при выходе. Ну и путаница в голове по поводу освобождения событий возникает. Допустим осбытие0 освободилось, но при проверке done на TRUE нас сразу выкинет из потока но не завершит. Ведь насколько я понимаю завершение потока происходит с помощью функции _endthreadex(). Т.о. почему бы просто не взять и не завершить этой функцией все потоки по очереди в IDM_EXIT? Вобщем хотелось бы поподробнее о выходе. 5\ Вроде все ок.
для того что бы визуально видеть что таймер срабатывает. А так можно и 0 Кстати что делать с отрисовкой раз в секунду моих данных? Архив с проектом
Большое спасибо за помощь. Это сообщение отредактировал(а) wallstreet - 13.3.2012, 14:00 |
||||||
|
|||||||
| feodorv |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Спасибо! В конце концов удалось скомпилиться и запуститься)))) Просто у Вас ошибка в Thread3: Мало того, что там совсем не нужно защищать код критической секцией, так ещё и EnterCriticalSection(&cs2); два разА прописано (типичный копи-паст баг)))) СтОит только оставить:
И обновление идёт)))) Правда, как я уже говорил:
Ну, это Вы уж как-нибудь сами))) Ну, в данном случае не нужно))) Так как у нас один поток = одно событие. При другом раскладе стОит сделать выбор...
А у меня не висит ни секундочки (release) В первоначальном варианте события hEvent0 не было, а без него поток пробуждался исключительно по таймеру. И сделав WaitForObject(s) (hThread1) мы бы зависли до тех пор, пока не сработал бы таймер, пробудив поток. Используя hEvent0, мы не зависим от таймера (при пробуждении первого потока).
Где?))) _endthreadex() вызывается функцией _beginthreadex() по окончании выполнения функции потока. А Вы функцию потока завершать никак не хотели))) И мы бы остались с тремя потоками при завершении программы. Их бы всё равно прибила операционная система (при возврате из WinMain) посредством TerminateThread, но этого допускать не следует, так как при внезапной кончине одного потока другой поток своими действиями может вызвать нарушение доступа.
Гм. Вот как раз по тем самым причинам. Представьте себе, Вы говорите программе "Exit", а она: "Access violation..." Не комильфо))) Самый лучший вариант - дать потоку завершиться самому. -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||||||
|
|||||||||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Оооо, да.
Ошибка зачетная была... Ну теперь все работает как часы. Примного благодарствую) |
|||
|
||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
вот EnterCriticalSection как раз имеет такую принадлежность, а то, что LeaveCriticalSection может освободить чужую секцию можно расценивать как избыточную функциональность, которая может приводить к различным ошибкам
я бы не советовал пользоваться таким свойством
судя по условию, задача учит просто синхронизировать доступ к массиву, управляемому разными потоками, это не значит, что на секциях должно быть все не надо пытаться думать о том, что какой-то поток дожен отработать раньше другого, это движение мыслей неправильное, и приведет лишь к потерям времени, денег, нервов если есть топологические отношения между потоками, значит они должны разрешаться синхронизаторами, по одному на каждое такое отношение, иначе стоит подумать о том, чтобы преобразовать такие потоки в один автомат отобразить, нарисовать - граница нечеткая, но если нарисовать, то здесь основной поток вообще должен просто отобразить готовую картинку, которую третий поток как раз и формирует -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Ок. Скажу иначе: потоку, захватившему критическую секцию, не передаются права владения ею (в отличии от мютекса). Может, но не обязательно приведёт. С другой стороны, если "an error occurs", то схему лучше переделать. Хотя, честно говоря, не понимаю, какая именно возникает ошибка. То, что неправильное применение критических секций может вызвать взаимную блокировку, несомненно. Интересное замечание))) Но в данном случае это требуется по условию задачи. Если будет такая возможность и желание, предложите свою схему, переделаем На здоровье))) -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Кажется, всё же, понимаю))) При отсутствии цикла в Thread1 всё было бы нормально. При наличии цикла возможно его зависание... Мдя))) Это сообщение отредактировал(а) feodorv - 15.3.2012, 02:18 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
угу
угу + включаем законы мерфи по условию задачи, очередность отработки потоков не регламентируется ) 1. заводим секцию x, охраняющую модификацию/чтение массива 2. заводим событие (или семафор) y, разрешающий перезапись данных массива 3. заводим событие (или семафор) z, разрешающий отрисовку данных массива 4. заводим поток a, который ресайзит массив (с учетом входа в x) и сигнализирует y 5. заводим поток b, который при активации y заполняет массив (с учетом входа в x) и сигнализирует z 6. заводим поток c, который при активации z рисует массив во временный растр (с учетом входа в x) и посылает команду на обновление окна 7. в WM_PAINT просто отрисовать готовый растр, если он имеется 6 и 7 пункт, по хорошему, требует также синхронизации доступа к глобальному растру, решать это можно как секцией, так и простой взаимоблокировкой, p.s.: если не понятно как реализовать синхронизацию доступа к глобальному растру взаимоблокировкой, могу потом показать Добавлено через 8 минут и 10 секунд + для большей интерактивности, на форме можно, разместить манипуляторы, управляющие первым потоком, например: для управления длиной массива и кнопкой, для "спуска" итерации первого потока, тогда потребуется еще одно событие, которого этот поток будет ожидать, перед ресайзом массива и, соответственно, которое будет сигнализировать кнопка -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| feodorv |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Они всегда включены))) Но если жить только по ним, то лучше не жить)))
Да, согласен. Просто есть желательная последовательность выполнения потоков (согласитесь, странно планировать программу так, чтобы пробуждались потоки в обратной последовательности, то есть сначала пробуждать поток с отрисовкой, потом пробуждать поток с инициализацией, и только потом с выделением памяти). Понятно, что реализовывать программу нужно исходя из того, что порядок выполнения и планирование потоков операцинной состемой может быть произвольными (с нашей, пользовательской, точки зрения). Это решает ОС.
Ок. А метафайл никак подойдёт под эту задачу?
Не понятно, что здесь непонятного, поэтому лучше показать, чтобы рассеять все сомнения)))) -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||
|
|||||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
судя по твоему обширному плану, они выключены, эти законы не для того, чтобы жить по ним, а для того, чтобы не заморачиваться, и жить по своим а процесс разработок - такая штука: чем дальше в лес, тем больше дров - не всегда может опираться на "желательную" логику работы программы, особенно тогда, когда эта логика нестабильна и может быть легко нарушена -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
если я правильно понимаю: emf, wmf? подойдет, конечно, только пользы от него конкретно в данной задаче будет 0, поскольку отрисовка такого файла будет идти не в потоке, а все в том же WM_PAINT (в потоке будет просто сформирован набор команд) лучше всего подойдет простой растр -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
План не обширный, а всего лишь подробный))) А фиг его знает, для чего эти законы, но если они действуют, то приходится с ними считаться)))) Потому и олинклюзив))) Ок! Плохо, что автор темы пропал куда-то... -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| wallstreet |
|
||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Честно признаться не знаю как сформировать мой массив в виде растового изображения. Поэтому без вашей помощи буду месяц разбираться((
ну почему же пропал, просто времени мало в последнее время на самообучение((( а так процесс идет!! ;) Это сообщение отредактировал(а) wallstreet - 22.3.2012, 13:11 |
||||
|
|||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
Width, Height - размерв растра PaintArray - метод отрисовки растра hMemBitmap - сам растр p.s.:код писал в браузере, контроль ошибок не вел -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| wallstreet |
|
||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Благодарю за ответ, но вопросов появилось еще больше((
Правильно ли я понимаю, что:
т.е. фактически делаем PrintScreen экрана?
По поводу метода отрисовки растра. Честно говоря у меня вообще ни одной мысли нет как я могу это сделать. Думал что растовая графика работает исключительно с имеющимися уже изображениями. А как создавать изображение ума не приложу. Т.е. насколько я понимаю растовая графика это просто разложение по пикселам изображения. А вот как превратить текст или число в изображение не могу даже представить. Тем более не могу понять зачем нам принт скрин рабочего стола(((( Короче в голове каша полная.. Огромная просьба разъясните что к чему. Это сообщение отредактировал(а) wallstreet - 27.3.2012, 16:31 |
||||
|
|||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
нет, фактически - "получаем вожжи" для его управления, но в данном случае нам он нужен только для того, чтобы создать растр, который имеет с ним аналогичные характеристики, чтобы его можно было отобразить на экране с помощью этой функции создают контекст изображения, совместимый с заданным, т.е. имеющий с ним совместимый формат
с помощью этой функции создают растр, совместимый с заданным контекстом, т.е. имеющий с ним совместимый формат, т.е. растр, который можно выбрать и манипулировать им в аналогичном контексте
ты это уже сделал (см. первый пост): цикл с TextOut, просто вместо hdc нужно указать hMemDC -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Вобщем сделал первый очень сырой вариант без таймера.
Основная задача для меня была сделать управление и научиться создавать растр. Ну и выводить его на экран когда надо. Не со всем удалось справиться, далеко не со всем. Итак вопросы: 1) Не могу понять почему после запуска всех потоков по очереди, в конце третьего не срабатывает InvalidateRect() Т.е. картинка создается, но не отображается. Стоит хоть чуть чуть изменить размеры окна, как она сразу отрисовывается. 2) Где нужно удалять массив, что бы при увеличении его размера не было выхода за пределы. Когда в скроллбаре выбираю размерность 10 к примеру, соответственно отрисуется массив 10х10, если после этого выбираю меньшую размерность все норм, но если большую, то сразу же работа прерывается. 3) массив нормально заполняется размерностью 10х10 если поставить больше, то начинают отображаться символы. По всей видимости где-то что-то не расчитал с типом данных(((( Так вот если подскажите где, буду признателен очень! Вот собственно ссылка на файл сырой проект Заранее благодарю за помощь в обучении. |
|||
|
||||
| GremlinProg |
|
||||||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
1. возвращаемся в самое начало:
2. булева переменная x_section лишняя, надо избавиться, главный вопрос: где критическая секция x (CRITICAL_SECTION), и зачем здесь hSemaphoreX, видимо тут уже путаница 3. семафоры, которые ожидают потоки не нужно снова включать из этих же потоков, вызывая для них ReleaseSemaphore, их всегда должно включать что-то внешнее: - a включает кнопка (основной поток) - y включает поток 1 - z включает поток 2 ну, раз появилась кнопка, значит здесь a - это тот самый синхронизатор, который включает первый поток a, вместо непонятного hSemaphoreX (на данном этапе это не так важно из-за первых двух ошибок) 4. Thread1 не перераспределяет память buf, он только создает массив (на данном этапе это не важно из-за первых двух ошибок), вобщем-то напрямую память трогать не обязательно, можно использовать какой-нибудь готовый контейнер, STL, например, std::vector 5. после отрисовки растра в потоке не вижу его обратной выборки из HDC и не вижу удаления HDC, если этого не делать будет утечка GDI-ресурсов и hMemBitmap будет хранить системный растр, а не тот, который рисуешь 6. hMemDC на WM_PAINT нужно создать свой, по той же схеме 7. hMemBitmap в таком случае требует синхронизации доступа из основного и 2-го потоков 8. не надо делать глобальными hScreenDC, hMemDC, hMemBitmap (не стоит), глобальным можно сделать например hMemBitmap, или просто другой HBITMAP, чтобы не делать ошибок на пустом месте 9. соответственно, не видно работы с критической секцией (ну раз ее нет, значит и не видно, но не видно даже попыток снхронизировать доступ к массиву)
InvalidateRect срабатывает, см. п. 5
это будет происходить через раз (с учетом исправления п.1), т.к. в HDC чередуется выборка hMemBitmap, см. п. 5
в потоке 1, он же занимается изменением размера массива
все что после этого, уже не имеет значения, т.к. потоков уже нет, см. п.1
пока так же не имеет значения, см. п.1 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||||||
|
|||||||||||||
| wallstreet |
|
||||||||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
мое незнание как реализовать ваши советы, завели меня в тупик.((
Но все по порядку:
Не могу понять как зациклить все потоки что бы они отрабатывали не один раз? Т.е. по срабатываюнию кнопки я освобождаю семафорХ, потом первый освобождает семафорУ, второй освобождает семафорZ а тот в свою очередь опять освобождает семафорХ или каким-то образом необходимо запускать поток через _beginthreadex()? 2. убрал булева переменную x_section (лепил горбатого к стенке, сам не понимаю зачем) Сейчас все потоки с первого по третий защитил критической секцией, для синхронизированной работы с непосредственной отрисовкой в WM_PAINT, которую тоже защищаю критической секцией. Все остальные потоки будут гарантированно выполняться в нужной последовательности за счет последовательного освобождения семафоров.
А как тогда я зациклю потоки что бы они не отображались всего один раз? 3. Те же вопросы с зацикливанием потоков.. Я просто не знаю, как это сделать, не понимаю принцип(. 4. Если делать с вектором то чем тогда займется первый поток ведь он, вектор, должен быть глобальным? 5. Пытаюсь делать так:
а растр вообще перестает отрисовываться. Кстати советуют удалять дескрптор контекста, который создавался функцией GetDC(), с помощью ReleaseDC(). Так вот Вы специально выбрали первый вариант (DeleteDC)? Если нет, то какой хендл (первый аргумент в ReleaseDC) использовать? 6. Вот что у меня получилось:
Опять же понять не могу, как он отрисует раст, если он тут еще не нарисован?!?!?! Ведь я же удалил дескриптор контекста растра еще в 3м потоке. 7.
а синхронизировать что конкретно, отрисовку? Т.е. пока создаем растр, не допускать к отрисовке в WM_PAINT? В данном случае я оградил от отрисовки все потки критической секцией, т.е. отрисовка не начнется пока все не закончат свою работу. 8. Так и поступил, только если сделать hMemBitmap типа BITMAP то будут проблемы вот тут:
поэтому она у меня HGDIOBJ типа. 9. Вроде бы сейчас попытался Сори, что так много вопросов, наверняка со многими из них я бы разобрался за ближайшие лет пять. Так, что спасибо за очередную попытку завести мой мозг с толкача Ссылка на проект Это сообщение отредактировал(а) wallstreet - 4.4.2012, 00:18 |
||||||||||||
|
|||||||||||||
| GremlinProg |
|
||||||||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
надо просто завести в потоках цикл (пусть он пока будет бесконечный):
потом можно будет его ограничить глобальным событием hAbort, чтобы по его включении все потоки спокойно завершали свою работу если это та же секция, то получится, что: 1. либо любая отрисовка окна будет блокировать потоки, которые используют массив 2. либо любой поток, который уже начал обработку массива, будет блокировать отрисовку окна, пока не завершит работу, т.е. приложение будет на это время тупо висеть (ты потом сам это увидишь, когда будешь задавать большие размерности массива) пока я бы не рекомендовал защищать WM_PAINT, это пока не такая страшная ошибка
циклом во всех потоках(см. выше)
пусть вектор будет глобальным, в чем проблема? в старом коде ты использовал в WM_PAINT HDC, созданный в потоке, поэтому растр и не рисуется, в WM_PAINT нужно создать свой HDC и выбрать в него битмап (в 6 почти все правильно, только ты забыл обратно выбрать растр и освободить контекст, т.е. тут сохраняется ошибка п.5)
конечно
не понял у меня для GetDC вызывается ReleaseDC, и в первом параметре тот же дескриптор, что и в первом параметре GetDC, т.е. HWND_DESKTOP или NULL, т.е. - "экран", DeleteDC вызывается только для CreateCompatibleDC
путаешь, ты удалил не растр, а контекст hMemDC, это разные вещи, растр находится в hMemBitmap по хорошему, как я уже говорил, следует синхронизировать обращение к hMemBitmap (но другим синхронизатором), у тебя в этом плане тут 2 ошибки: 1. синхронизируется только вызов BitBlt, хотя 3-й поток может изменить растр еще на этапе SelectObject 2. в 3-м потоке используется та же переменная, что и в основном, на WM_PAINT - это hMemBitmap (да, в 8 ты об этом правильно подметил), т.е. это означает, что пока 3-й поток рисует массив, доступ к этой переменной должен быть блокирован, поэтому я и рекомендую вместо глобальной hMemBitmap использовать какую-нить другую, например: hMemSharedBitmap, в которую 3-й поток, после завершения отрисовки массива, будет копировать hMemBitmap, и которую будет использовать основной поток в WM_PAINT, вот доступ к этой переменной и надо синхронизировать ну, и теперь, когда ты зациклишь все потоки, потребуется удалять hMemSharedBitmap, перед очередным ее обновлением в 3-м потоке, чтобы не было утечки GDI-ресурсов, для этого нужно вначале инициироввать ее в значение NULL, и перед любой модификацией проверить на NULL и удалить, в случае, если она не NULL с помощью функции DeleteObject p.s.: неблагодарное это дело, пальцев не хватит, проще написать код, feodorv, не желаешь присоединиться? ты же можешь, я знаю -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||||||||
|
|||||||||||||||
| wallstreet |
|
||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Делаю вот так:
Поток3
Отрисовка данных:
Где в части создания и отрисовки растра я допускаю ошибку? Проект Это сообщение отредактировал(а) wallstreet - 4.4.2012, 16:16 |
||||
|
|||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
установка и использование hMemSharedBitmap неправильная,
не надо для нее создавать растр (CreateCompatibleBitmap), ей надо просто присвоить значение hMemBitmap:
Enter и Leave здесь, соответственно, вход и выход из эксклюзивного участка кода, x и shared - сами синхронизаторы: x - защищает модификацию и чтение массива, а shared защишает доступ к переменной hMemSharedBitmap -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Прошу прощения, что ушёл с сумрак, дела зовут... GremlinProg Правки супер! То, что надо))) Только два момента, замеченных при беглом просмотре: 1/ что такое cx и cy в Thread3 и в WM_PAINT? Как я понимаю, в Thread3 мы должны высчитывать размер битмапа исходя из начальных данных (то есть buf[count_row][count_column] должен порождать cx и cy путём подсчёта места, необходимого под TextOut... Если же сx и cy высчитывать исходя из размера окна, то при ресайзе этого самого окна могут возникнуть неприятные артефакты. 2/ рисовать стОит только тогда, когда hMemSharedBitmap не NULL. wallstreet Очень прошу обратить внимание на
То есть нужны 2 критические секции, а не одна: x - синхронизирует доступ к buf в Thread1, Thread2, Thread3, а shared - к hMemSharedBitmap в Thread3 и WM_PAINT основного потока. Ну и опять же, хочется весь проект с правками... Это сообщение отредактировал(а) feodorv - 5.4.2012, 11:17 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| wallstreet |
|
||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Всем доброго дня.
Благодарю за разъяснения, теперь ясно как никогда. Подровнял я проект под ваши советы, даже вектор прикрутил. Но следуя сложившейся традиции где-то что-то напортачил и матрица отображается криво. А точнее одна ее строка только ито не с самого начала. Что касается:
я инициализировал переменные ширины и высоты битмапа значением выбраным пользователем в скроллбаре умноженным на 30 (ширина между цифрами в битмапе в пикселях) при нажатии кнопки "ОК". Выглядело это вот так:
но можно задать высоту и ширину во втором потоке, сразу после заполнения матрицы значениями. вот так:
Благодарю за участие, вот, собственно, ссылка для скачивания проекта: Ссылка на проект Это сообщение отредактировал(а) wallstreet - 6.4.2012, 18:30 |
||||||
|
|||||||
| feodorv |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Посмотрел код одним глазом и... ужаснулся((( Как же можно допускать такое нагромождение операторов, переменных... Про начало не знаю, но то, что одна строка:
Ну как минимум count_column во втором форе нужно переинициализировать в 0. Вообще, все векторные прибомбасы стоило отложить на самый конец, имхо. Как максимум нужно разобраться с итераторами (что выводит TextOut?). По замечаниям: 1/ мы с GremlinProg договорились не использовать грязных трюков с захватом критической секции в одном потоке и освобождением в другом. Надо исправить 2/ откуда взялась и что защищает критическая секция csX? 3/ cx и cy - есть характеристики битмапа hMemSharedBitmap. Менять их нужно только в тот момент, в который изменяется значение hMemSharedBitmap, а не в любой произвольный момент. Переменные hMemSharedBitmap, cx, cy защищаются критической секцией csShared. Соответственно, ::scrlh - есть характеристика вектора (в прошлом - буфера), менять значение этой переменной стоит тогда, когда мы изменяем размер вектора (или буфера). Вектор и ::scrlh защищаются критической секцией cs. 4/ Что делает этот код:
??? 5/ таймер больше не используется? 6/ какое отношение имеет инициализация семафоров и запуск потоков к Dialog1??? Что будет, если Dialog1 вызвать более одного раза? Сколько будет потоков? Сколько семафоров? Зачем InvalidateRect(hDlg, FALSE, TRUE); в Dialog1() при WM_COMMAND IDOK? 7/ зачем нам теперь глобальные переменные
8/ зачем семафоры, когда хорошо жили при событиях? Чего-то я ещё заметил, но уже забыл.... Это сообщение отредактировал(а) feodorv - 8.4.2012, 18:16 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||
|
|||||||
| wallstreet |
|
||||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Ну так еще бы, проект сырой очень, да и вообще) На самом деле постоянно что-то меняю что-то пробую, поэтому и переменных куча ненужных. Вобщем впреть постараюсь сразу удалять. Хорошее замечание!
Да, точно. Теперь матрица заполняется правильно, но неправильными числами. (сейчас я изменил заполнение на рендомное) А с чем конкретно в итераторах? Я неправильно с ними работаю? Пробовал в консоле данную структуру создания и вывода, все работало как часы. 1/ ОК. Убрал секцию cs, только теперь смущает, что первый поток, который по идее должен был заниматься выделением памяти под данные, не занимается ничем. Ну да ладно.. 2/ сsX - защищает модификацию и чтение вектора 3/
Если я инициализирую значения сх и су в потоке3, в секции csShared то растр не отрисовывается в WM_PAINT.
Значение переменной ::scrlh изменяет локальная переменная scrlh диалога1 на значение выбранное скроллбаром в обработке нажатия кнопки "ОК". Собственно оную нажав мы и изменяем исходные параметры размерности моего вектора и растра. Т.е. мы открыли диалог1, выбрали размерность матрицы, нажали "ОК" и матрица должна сразу же поменять размер и перерисоваться на главном окне. Именно поэтому, как мне казалось, правильнее было прилепить запуск потоков к обрабоке нажатия кнопки ОК, что я и делал, но вопрос с Таймером для меня был открыт. Вобщем, если с потоками все понятно, то как изменить значение переменной ::scrlh в потоке2, для меня загадка?!?! В принципе можно создать еще одну переменную, локальную для потока2 и брать значение глобальной ::scrlh, но есть ли в этом смысл? 4/ Честно признаться не помню уже какую цель преследовал, но явно над чем-то эксперементировал методом тыка) 5/ Таймер будет скоро. Если не сложно, подскажите как я могу его запускать из диалога1 и где его устанавливать, т.к. он запускает потоки, а они у меня запускаются при создании окна и второй раз их запускать таймером будет неправильно. 6/ Ну основную логику описал в п. 3. Просто думал так, что запуск потоков с созданием и отрисовкой матрицы необходимо делать после того как пользователь определится с ее размером, а самым лучшим для этого подтверждением является нажатие на кнопку "ОК". Сейчас то, с вашей помощью, я уже понял как можно по другому (страшно сказать правильно 7/ Удалил ненужные, а вот hMemBitmap очень даже нужная. Это наш растр, который мы создаем в потоке2, а в потке3 инициализируем им hMemSharedBitmap. Однако в глобале ей делать нечего и это факт) 8/ Ну моя цель работы над данным проектом это учеба. С сбытиями разобрался, теперь представилась возможность попрактиковаться с семафорами. Почему бы и нет Ссылка на проект тут -> обновленный вариант Это сообщение отредактировал(а) wallstreet - 10.4.2012, 10:09 |
||||||||
|
|||||||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Вот я прописал таймер.
Он у меня создается в момент создания окна. Создается без задержек и сразу же запускает потоки, но потоки не отрисовывают раст, т.к. семафорХ не запущен. Этот семафор освободит диалог1 после того как пользователь определится с размерностью матрицы, которую хочет видеть на экране и нажмет кнопку "ОК". Предположим пользователь сидит и смотрит на пустое окно и размерность массива не выбирает, даже диалог1 не открывает. Так вот мне интересно, в этот момент мой таймер что делает, создает раз в секунду поток, который ожидает освобождения семафораХ? Так вот вопросы эти появляются только потому, что после того как я определю размерность матрицы в диалоге1 программа отрисует один раз мой растр и все. Да еще и непонятно почему заполняет только матрицу 10х10 правильно, а при заполнении 5х5, к примеру, то будет она выглядеть вот так: ![]() хотя должен был начинаться второй ряд с 5 6 7 8 9, ну и тд. И что самое главное картинка не перерисовывается с новой матрицей, хотя вроде и цикл есть в потоках, но не хочет. Почему?( Ссылка на проект тут=>проект Заранее благодарю за ответы! Это сообщение отредактировал(а) wallstreet - 11.4.2012, 17:45 |
|||
|
||||
| GremlinProg |
|
||||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
таймер должен заменить семафорХ, а не дополнить, просто удали семафорХ, диалог теперь не должен запускать поток, т.к. он запускается таймером, но возникает еще один конфликт, подобный hSharedBitmap: переменная scrlh в таком случае тоже должна быть защищена из диалога и в потоках теперь по коду: 1. у тебя опять путаница в ролях потоков: зачем первый поток очищает массив, когда он должен задавать его размер? 2. ладно, очищает, но почему без синхронизации? 3. "ЗАПОЛНЕНИЕ ВЕКТОРА" ну сам же пишешь: "ЗАПОЛНЕНИЕ", т.е. заполнение его данными, а почему я вижу в цикле push_back? второй поток не должен вызывать ни каких операций, связанных с изменением размеров вектора, этим должен заниматься первый поток, соответственно, раз cx и cy напрямую зависят от scrlh, второй поток тоже не должен трогать эти переменные, оставь и эту работу первому потоку не создает, а пробуждает, или запускает, на счет семафораХ уже сказал, на данный момент его должен заменить таймер в принципе, задача так и стоит: по таймеру пускать всю цепочку событий, пользователю, конечно это может не так интересно наблюдать, я бы мог предложить более интересный вариант: заполнять массив не тупо значением j++, а добавить сюда элемент уникальности, например factor * j++, тогда factor будет один раз инициализироваться перед заполнением массива, например так:
тогда всякий раз, после запуска цепочки, картинка будет меняться, пользователю будет не так скучно, ну, или можно вообще отвязать изменение factor от потоков, а менять его значение в диалоге, вручную
ну, это потому, что у тебя тут стоит TRUE:
а должно быть как минимум FALSE, ну а как оптимум: hSemaphoreX тут быть не должно, хотя, если бы задача стояла: пускать первый поток либо по таймеру, либо по активности пользователя, то можно было бы и оставить, это интересная практика, да и пользователю хорошо: изменения сразу вступают в силу, после закрытия диалога
а что не нравится? тут все верно:
это означает, что для 10x10 значения массива будут выведены в 10-чной системе счисления, для 5x5 - в 5-чной и т.д. если надо все выводить в 10-чной, передавай в последний параметр 10, а не vv.size() -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||||
|
|||||||||||
| feodorv |
|
||||||||||||||||||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
Здесь я не совсем согласен Изначально Event0 нужен был только для того, чтобы пробудить Thread1 не дожидаясь срабатывания таймера (то есть для корректного завершения программы). В сущности, для этого же нужен SemaphoreX, ни больше ни меньше. То есть он нужен (если им правильно пользоваться):
Конечно, так не годится. Ожидается и таймер и семафор одновременно. Зачем? Почему не так:
Ээээ... Увидел
Опять же, не совсем согласен cx и cy используются в отрисовке битмапа:
Менять отдельно cx, cy и hMemSharedBitmap не стоит!!! Иначе говоря cx и cy нужно менять в Thread3 в момент
То есть:
Тут же встают проблемы инициализации и очистки
Если хочется всё стартовать через Dialog1, то можно сделать так:
Соответственно в Dialog1:
Соответственно в WndProc убрать код инициализации hTimer, ThreadXXX и
Можно launchDialog вызвать и в момент окончания инициализации главного окна (принудить пользователя к действиям), но это особая история...
Во-первых, vv.clear() стоит делать только после завершения всех потоков. Во-вторых, потоки нужно предварительно пробудить. В-третьих
это лишнее, а вот hMemSharedBitmap освободить нужно!!! В четвёртых, надо освободить таймер. В пятых, перед ожидаем потоков, стоит проверить, что они вообще были запущены. То же к таймеру и семафорам. Да я не в притензии, я для дела сугубо))) Это сообщение отредактировал(а) feodorv - 12.4.2012, 18:18 -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
Event0 - это семафорХ? если так, то изначально этот семафор пускал первый поток, о завершении потоков мы как-то уже договорились, что пока на нем заморачиваться не будем, потом, для завершения всех потоков лучше сделать одно событие hAbort, которое и заменит флаг done если не опираться на cx и cy в 3-м потоке, при создании растра, то да, так будет безопасно для основного потока, хотя он может получить эту же информацию из растра, через GetObject, на счет безопасности в основном потоке я бы как раз пока особо не переживал, я сейчас говорю об инициализации растра в 3-м потоке, теоретически, раз от размера вектора зависит размер растра, и размер вектора выставляется в критической секции x, то разумно было бы и размер растра выставлять/получать в этом критическом участе кода, тогда нет разницы, в каком потоке это будет сделано -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Всем спасибо за помощь.
кое что подправил, завтра думаю добью если время будет. Ссылка на проект =>проект |
|||
|
||||
| feodorv |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
GremlinProg
Конечно, при отрисовке битмапа неверные cx и cy не скажутся на безопасности выполнения основного потока, но дело в принципе:
Между Thread1 и Thread3 может случится WM_PAINT. При этом hMemSharedBitmap ещё старая, а значения cx и cy уже новые, не когерентные с hMemSharedBitmap...
Вот это было бы лучше всего (чтобы не было путаницы), а от cx и cy можно будет отказаться вообще...
Прошу прощения, но эта мысль никак не желает достигнуть нужных отделов моего слабеющего мозга))) wallstreet
В смысле??? -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
||||||||||
|
|||||||||||
| GremlinProg |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
равно как и между Thread3 и WM_PAINT может случиться Thread1 и Thread2 reserve не задает размер вектора, здесь нужен resize
либо отказаться, либо завести еще пару, ибо под одним синхронизатором кто-нибудь обязательно будет в пролете: либо растр, либо WM_PAINT
судя по коду, она все же нашла, что искала -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||
|
|||||
| wallstreet |
|
||||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Ну, полностью отказаться я не знаю как, т.к. при создании растра hMemBitmap, в третьем потоке, мы задаем его размеры.
В этот момент еще нет хендла растра из которого можем вытащить высоту и ширину. Т.о. я оставил инициализацию cx и cy в первом потоке исключительно для создания первого растра hMemBitmap. В то время как для отрисовки в WM_PAINT я ширину и высоту вытаскиваю из уже готового растра hMemSharedBitmap, которому до этого присваиваю hMemBitmap. Если вы покажете способ избавиться от сх и су полностью, буду признателен.
Видимо я неполноценно выразил свою мысль, но если вы попробуете размер матрицы установить, предположим, в 10х10 с помощью скроллбара, а затем второй раз, уже рисующийся растр изменить на размер 5х5 с помощью все того же скроллбара, то заметите как он где-то на секунду приостановит отрисовку и потом уже нарисует правильный размер матрицы, а при увеличении размера, такой задержки не последует. Так вот меня интересовали причины по которым отрисовка подтормаживается при уменьшении размера растра. Собственно на выше приведенный участок кода я и стал грешить, хотя может зря, может причина в другом? ссылка на проект:скачать проект |
||||||||
|
|||||||||
| GremlinProg |
|
||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
это равнозначно такому коду:
т.е. таким кодом ты дважды меняешь размер вектора, причем в конечном счете он оказывается пустым зачем тебе это понадобилось, я пока не вникал, но если это и есть твоя операция по изменению размера вектора, то любое обращение к его элементам после этого должно генерировать ошибку -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||
|
|||||||
| GremlinProg |
|
||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
упс, недопонял я этот код привел для WM_PAINT'а, т.е. не для 3-го, а для основного потока -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||
|
|||||||
| wallstreet |
|
||||||||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
да да да, именно так я и вытаскиваю высоту и ширину из hSharedBitmap в WM_PAINT, но не использовать сx и cy в третьем потоке не знаю как. Хотя по большому счету если не запустится поток2, то не запустится и поток3, а второй запускается только после того как зпускается поток1 в котором инициализируются сx и су. Так что между потоками нестыковок в работе не должно быть, а в WndProc при отрисовке берется высота и ширина из битмапа, так что думаю все ок тут с синхронизацией.
Я понимаю так. Поток1 ресайзит вектор. Предположим, что он уже заполнен значениями 1, 2, 3, 4, 5. Так вот если я изменяю его размер вот так:
то получу в результате: 1, 2, 3, 4, 5, NULL, NULL, NULL и если я в дальнейшем не удалю значения оставив только размерность, то используя push_back() во втором потоке, значения вставятся непонятно как для меня. Т.е. если убрать удаление элементов вектора из потока1, то WM_PAINT отрисовывает черный квадрат заданой размерности, без чисел. Изначально думал резервировать память под вектор, если его размер 0, в потоке1 функцией reserve(), а в потоке2 заполнять исходя из его capacity() простым циклом. Если же вектор.size() > 0 тогда изменять его размер функцией resize(), но как проблему решить с очисткой от значений я не знал поэтому все на выходе получалось через стерни к звездам. Добавлено через 14 минут и 11 секунд вообще думал сделать изменение размера вектора и его заполнение как-то так: Поток1
Поток2
Но этот код не работает, матрица отрисовывается один раз и вылазит ошибка Debug Assertion Failed! Expression: vector iterators incompatible |
||||||||||
|
|||||||||||
| GremlinProg |
|
||||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
ну смотри, в первом потоке задаешь размер массива:
а во втором его заполняешь:
если проблем с синхронизацией нет, значит ошибок тут тоже не будет, и не важно, какой размер был на предыдущей итерации, черный квадрат у тебя точно не из-за того, что сохраняются старые значения в массиве -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||||||
|
|||||||||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
эээ.. стесняюсь спросить auto это что? насколько я понимаю it это итератор, но чем он отличается от std::vector<std::vector<int>>::iterator it? Это сообщение отредактировал(а) wallstreet - 18.4.2012, 13:53 |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
ни чем не отличается -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| wallstreet |
|
||||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Последовал вашим советам и вроде все заработало, но зависание при уменьшении матрицы осталось все равно.
Честно признаться работало и раньше все так же, когда вместо предложенного вами варианта я использовал в потоке1 просто
Возможно я просто еще догнать не могу сути мысли, но до подобных синтаксических конструкций типо:
я самостоятельно бы не дошел, во всяком случае сейчас, и меня это ужасно расстраивает. Ссылка на проект Это сообщение отредактировал(а) wallstreet - 18.4.2012, 15:19 |
||||
|
|||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
это всего лишь С++,
то же самое можно было записать проще:
и это было бы правильно p.s.:на счет зависания, пока не смотрел, пока нет возможности -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
Я вот тут подумал, таймер запускает потоки и отрисовывает раст с задаными параметрами, в часности с размером ::scrlh, который я беру из глобальной переменной в первом потоке и инициализирую сх и су, а в этот момент уже поменял глобальную переменную через диалог1.
И создается такая ситуация, что я меняю глобальную ::scrlh нажимая "ОК", именно в тот момент когда отрисовывается в WM_PAINT раст со старым значением ::scrlh, которая защищена критической секцией csShared. Так вот если защитить в диалоге1 изменение глобальной ::scrlh с помощью секции csShared, что бы инициализация глобальной ::scrlh проходила между тактами отрисовки по таймеру? Я спрашиваю, потому, что на домашнем компьютере это подтормаживание не видно почему-то))) |
|||
|
||||
| GremlinProg |
|
||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
я притормаживаний ни каких не вижу,
но тут конечно еще есть проблемы синхрнизации: 1. scrlh меняется в диалоге (в основном потоке) и читается в потоке 1, есть риск попасть в такую ситуацию, когда scrlh изменится в середине цикла:
в конечном счете, получится искажение массива в потоке scrlh читается под секцией csX, если в диалоге так же менять ее под секцией csX, то все будет хорошо 2. GetObject в 3-м потоке совершенно не нужна, она нужна в WM_PAINT, под секцией csShared, ничего стршного тут конечно нет, т.к. GetObject защищен той же csShared, просто зачем тратить время 3-го потока на работу основного (WM_PAINT) пока больше ничего военного не заметил Добавлено @ 07:34
это я еще не очень понял, т.е. ты думаешь, что если изменения scrlh защитить csShared, то отрисовка массива будет синхронизирована с этим изменением? если так, то нет, это просто приведет к тому, что ты не сделаешь эти 2 операции одновременно ( WM_PAINT и scrlh ), hSemaphoreX у тебя и так актуализирует изменения пользователя на сколько это только возможно, т.к. после
первый поток, если не загружен, сразу начинает работу с новыми параметрами Это сообщение отредактировал(а) GremlinProg - 19.4.2012, 07:35 -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
||||||
|
|||||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
||||
|
||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 9 Всего: 45 |
То есть всё? На этом завершаем?))) Тогда, как любит говорить bsa, пометь тему решённой))) -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| wallstreet |
|
|||
|
Бывалый ![]() Профиль Группа: Участник Сообщений: 153 Регистрация: 11.8.2011 Репутация: нет Всего: нет |
ок
|
|||
|
||||
![]()
|
| Правила форума "C/C++: Системное программирование и WinAPI" | |
|
|
На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы . Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |