Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как из thread'а безопасно перерисовать элемент главного окна?  (Прочитано 18822 раз)
0 Пользователей и 1 Гость смотрят эту тему.
jur
Помогающий

lt
Offline Offline

« : 25-03-2009 20:33 » 

Привет!

У меня в thread'е запускается процесс, который перерисовывает картинку. Он это делает посредством DirectX. Все работает нормально.

Но мне понадобилось в основном окне приложения отображать прогресс-бар, который должен соответствовать положению отображаемой картинки (навроде отображения положения текущего кадра при проигрывании киношки в любом плеере).

Казалось бы, никаких проблем. Из thread'а делаю PostMessage с собственной командой для передвигания прогресс-бара. Однако, через несколько минут весь интерфейс главной программы разваливается, выскакивают непонятные окошки насчет нехватки ресурсов и прочее. Прекратить это безобразие можно только принудительно убив приложение.

Создается впечатление, что thread посылает свои сообщения слишком быстро. Они забивают какие-то системные очереди и все рушится.

Как бы организовать перерисовку прогресс-бара более безопасно? Чтобы лишние сообщения от thread'а не разрушали программу? Заводить какой-то флаг?... Подскажите, пожалуйста!

Спасибо!
Записан

MPEG-4 - в массы!
Mike_I
Участник

ru
Offline Offline
Пол: Мужской
Mike


« Ответ #1 : 25-03-2009 20:42 » 

Я бы попробовал либо использовать мьютекс. Функ: CreateMutex(...).

Либо событие. Класс: CEvent.
Записан

Nothing fails like success.
jur
Помогающий

lt
Offline Offline

« Ответ #2 : 25-03-2009 22:00 » 

Не получается чего-то... Я в thread'е даже SendMessageTimeout пробовал - один черт... Через какое-то время программа рушится...

Пробовал завести флаг, который взводится при запросе перерисовки (т.е. в thread'е), а сбрасывается в процедуре OnDrawItem контрола прогресс-бара. Если флаг еще взведен, то из thread'а повторные запросы на перерисовку не посылаются. То же самое... Крах...

Кроме того, непонятно, где и как использовать мьютекс. Я забыл упомянуть, что главная программа - простое Dialog based приложение. Получается, что любой асинхронный запрос что-то сделать с контролом вызывает сбой программы (через некоторое время, когда очередь забьется).

Лобовое решение - завести в головной программе таймер миллисекунд на 50-100, и по нему периодически обновлять контрол прогресс-бара текущим положением моей картинки (точнее, ее номером в буфере на 256 картинок). Это работать будет. Но какое-то корявое решение... Ламерское... А как сделать красиво - ума не приложу?...

Записан

MPEG-4 - в массы!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #3 : 25-03-2009 23:44 » 

jur, покажи кодом как ты это делаешь. Как вызываешь из треда, как обрабатываешь в диалоге.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RuNTiME
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 26-03-2009 08:38 » 

jur, зачем тебе вообще использовать сообщения? Когда ты запускаешь поток, ты можешь передать в него указатель на некоторую структуру, в которой будет поле, отражающее текущий прогресс в числовом виде. Таким образом получиться, что структура будет доступна и из потока и из основной нити. Из главного потока программы запускаешь таймер с помощью функции:
Код:
UINT_PTR SetTimer(
    HWND hWnd,
    UINT_PTR nIDEvent,
    UINT uElapse,
    TIMERPROC lpTimerFunc
);
Периодически проверяешь значение поля структуры в обработчике таймера и на основе его значения выставляешь положение прогрессбара.
Записан

Любимая игрушка - debugger ...
zubr
Гость
« Ответ #5 : 26-03-2009 09:36 » 

Решение через таймер действительно ламерское, имхо. Надо смотреть в сторону потоко-безопасности (критические секции или мьютексы).
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #6 : 26-03-2009 09:56 » 

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

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
jur
Помогающий

lt
Offline Offline

« Ответ #7 : 26-03-2009 21:20 » 

У меня там код довольно объемный, да и на железо завязан. Поэтому я выделил проблему в автономное приложение. Приложение Dialog based, которое по таймеру (с периодом 30 миллисекунд) обновляет прогресс бар. Вот как выглядит нормальное окошко приложения:



(Это малюсенькое окошко на здоровенной Студии ;-)

Оно себе крутится, а я по нему Far'ом повожу, на Оперу переключусь, этот форум почитаю. И вдруг - вот оно, сломалось... Выглядит это дело вот так:



Что за фигня такая?... Где я напортачил?

P.S. Похоже, пока готовил автономное приложение, нашел, где "собака порылась" :-) Черт побери! Просто не заметил, что в функции перерисовки объекта завожу новый Pen, а удалить его забыл... Видать система мне все выделяла и выделяла новые пены, пока не возмутилась: "Ну сколько же можно?!"...

Поэтому на будущее я завел класс карандаша и кисти (образчики взял с превосходного сайта Reliable Software, перевод SoftCraft).

Вот код класса:

Код:
class SPen
{
public:
    SPen (HDC hdc, COLORREF color)
        : _hdc (hdc)
    {
        _hPen = ::CreatePen (PS_SOLID, 0, color);
        _hPenOld = (HPEN)::SelectObject (_hdc, _hPen);
    }
    ~SPen ()
    {
        ::SelectObject (_hdc, _hPenOld);
        ::DeleteObject (_hPen);
    }
private:
    HDC     _hdc;
    HPEN    _hPen;
    HPEN    _hPenOld;
};

class SBrush
{
public:
    SBrush (HDC hdc, COLORREF color)
        : _hdc (hdc)
    {
        _hBrush = ::CreateSolidBrush (color);
        _hBrushOld = (HBRUSH)::SelectObject (_hdc, _hBrush);
    }
    ~SBrush ()
    {
        ::SelectObject (_hdc, _hBrushOld);
        ::DeleteObject (_hBrush);
    }
    operator HBRUSH () { return _hBrush; }
private:
    HDC     _hdc;
    HBRUSH  _hBrush;
    HBRUSH  _hBrushOld;
};

Позор на мои седины...

Спасибо за помощь, друзья! Проблема, вроде, разрешилась (тьфу!, тьфу!, тьфу!). Если кому интересно, прикладываю мое пробное приложение. Проблема крылась в функции draw_item_progress. Я в ней завожу карандаши/кисти, а удалить их забыл. Только восстанавливал прежние. После применения SPen/SBrush проблему как рукой сняло.


* CinemaProgress_probe.zip (143.76 Кб - загружено 809 раз.)
« Последнее редактирование: 26-03-2009 21:25 от jur » Записан

MPEG-4 - в массы!
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #8 : 26-03-2009 22:03 » 

а зачем такие классы неудобные ? ) Ведь придётся каждый раз в WM_PAINT вызывать конструктор и деструктор. Когда мождно 1 раз при инициализации окна
« Последнее редактирование: 26-03-2009 23:28 от Алексей1153++ » Записан

jur
Помогающий

lt
Offline Offline

« Ответ #9 : 26-03-2009 22:28 » 

а зачем аткоие классы неудобные ? ) Ведь придётся каждый раз в WM_PAINT вызывать конструктор и деструктор. Когда мождно 1 раз при инициализации окна

А мне - наоборот, они показались весьма удобными :-) Я ведь этого WM_PAINT'а вообще не вижу, я пользуюсь функцией OnDrawItem.

Дело в том, что я решил построить программу в виде головного модуля и кучи вспомогательных DLL'ок. Головной модуль - навроде BIOS'а в персональнике: он предоставляет несколько объектов отображения и все. Это окно графики, два блока текста, восемь функциональных клавиш и т.п. Ничего больше он не знает и знать не хочет. Некоторые объекты в принципе могут иметь вообще собственные функции рисования. Для этого главная программа в своей функции OnDrawItem просто вызывает их функции DrawItem и все дела. А думать, какие карандаши/кисти им могут понадобиться - не барское это дело :-) Поэтому применение этих классов - весьма удобная штука, т.к. не грузит головную программу всякой частной фигней. Понадобилась модулю новая кисть - за ради Бога, используй, что хочешь!

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

;-)

P.S. Мне бы еще научиться закрывать thread, созданный в DLL-ке... Пока глухо...

Записан

MPEG-4 - в массы!
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #10 : 26-03-2009 23:26 » 

ты этого сообщения не видишь ? А оно есть (с) Улыбаюсь

отвлечённый пример:

у тебя:
Код:
for(int i=0; i<300; i++)
{
   Sleep(1);
   рисуем красивое окно

   рисуем ещё красивое окно
   Sleep(1);
}

а я предлагаю

Код:
Sleep(1);
for(int i=0; i<300; i++)
{
   рисуем красивое окно

   рисуем ещё красивое окно
}
Sleep(1);


что более производительно ?

к тому же, раз пользуешься MFC, почему бы не пользоваться CPen, CBrush, CDC ? Улыбаюсь
« Последнее редактирование: 26-03-2009 23:28 от Алексей1153++ » Записан

Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #11 : 27-03-2009 05:09 » 

Я так и думал. Ага

Поэтому на будущее я завел класс карандаша и кисти

А если внимательно посмотришь на форуме, то найдёшь гораздо более изящное решение наших мастеров STL для этой цели. Я правда так с ходу не нашёл. Давно было.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
jur
Помогающий

lt
Offline Offline

« Ответ #12 : 27-03-2009 08:45 » 

ты этого сообщения не видишь ? А оно есть (с) :)

;-)

отвлечённый пример:

...

что более производительно ?

Никакого сомнения! Я именно так делаю с фонтами, т.к. это более серьезная процедура. А перья/кисти - штука простая, но меняются часто, нужно то одним, то другим пером рисовать. Поэтому я склонился к простоте и удобству :-)

к тому же, раз пользуешься MFC, почему бы не пользоваться CPen, CBrush, CDC ? :)

Я не пользуюсь MFC. Точнее, немного пользуюсь ею только в головной программе. А в DLL'ках - чистый, незамутненный Win API :-)

А если внимательно посмотришь на форуме, то найдёшь гораздо более изящное решение наших мастеров STL для этой цели. Я правда так с ходу не нашёл. Давно было.

Так как же я найду, если даже ты не нашел! :-) Попробую, конечно, однако я в STL совсем не силён... В двух словах: чем удобна эта STL? (Забыл уточнить, я разрабатываю простые программы управления прибором, а не какие-то серьезные компьютерные приложения.)

P.S. Поискал, пока нашел только тему "Замена MFC и WinAPI".

Записан

MPEG-4 - в массы!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #13 : 27-03-2009 09:32 » 

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

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
sss
Специалист

ru
Offline Offline

« Ответ #14 : 27-03-2009 09:44 » 

jur, раз уж пишешь на чистом API и используешь простые перья и кисти, возможно, для ускорения стоит воспользоваться stock объектами GDI? Их не надо создавать/уничтожать. Смотри функцию GetStockObject и описание в MSDN...
Записан

while (8==8)
jur
Помогающий

lt
Offline Offline

« Ответ #15 : 27-03-2009 10:17 » 

jur, у меня просто времени не было тщательно искать. А в какой это теме было  или автора не помню... Посмотрю на досуге.

Большое спасибо!

А преимущество, что тебе не надо отдельный класс под каждый объект делать, ведь принцип у них один Create - Delete.

Так там классов-то этих... Два всего :-) А удаляются эти GDI по-разному, например, DC в памяти нужно удалять DeleteDC.

jur, раз уж пишешь на чистом API и используешь простые перья и кисти, возможно, для ускорения стоит воспользоваться stock объектами GDI? Их не надо создавать/уничтожать. Смотри функцию GetStockObject и описание в MSDN...

Да мне, вообще-то, ускорять не надо, у меня была проблема с поломкой. А stock объекты мне не подходят - у меня несколько разных нестандартных цветов.

Записан

MPEG-4 - в массы!
jur
Помогающий

lt
Offline Offline

« Ответ #16 : 27-03-2009 18:25 » 

2 Джон

Я процитировал твою подпись: "Я вам что? Дурак? По выходным и праздникам на работе работать.  По выходным и праздникам я работаю дома." коллегам по работе! Долго и дружно ржали с горьковатой примесью правдивости её содержания... ;-)))

Записан

MPEG-4 - в массы!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #17 : 27-03-2009 19:38 » 

Да уж, было времечко, когда это был чёрный юмор со слезами на глазах. Суровая правда жизни.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
jur
Помогающий

lt
Offline Offline

« Ответ #18 : 27-03-2009 21:09 » 

Ёлки... Какой к чертям юмор?... Голимая правда жизни...

;-)

Записан

MPEG-4 - в массы!
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines