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

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

ru
Offline Offline

« : 14-10-2010 09:07 » 

Есть форма, в форме кнопка.
По OnClick запускается процедура, довольно долгоиграющая.
Пока крутится процедура, окно формы совершенно мертвое. Добавил "this.Refresh()". В окне стали отображаться изменения, происходящие в процессе. Но при попытке прокрутить слайдер окно опять застревает в положении "не отвечает".

Черт с ней, запустил процедуру как поток. И получил сообщение:
Цитата
Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "textBox1" не из того потока, в котором он был создан.

Что тут еще можно сделать?
Записан
Алексей++
кот глобальный и пушистый
Глобальный модератор

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


« Ответ #1 : 14-10-2010 09:46 » 

передать в поток данные, а не ссылку на контрол. Улыбаюсь
Записан

Daniloff
Помогающий

ru
Offline Offline

« Ответ #2 : 14-10-2010 10:00 » 

у меня поток должен в разные контролы выводить данные в процессе работы. А низя!
Попробовал BackgroundWorker прикрутить. Но у него есть только уведомление родительского процесса о прогрессе выполнения.
Записан
Алексей++
кот глобальный и пушистый
Глобальный модератор

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


« Ответ #3 : 14-10-2010 10:23 » 

Daniloff, как в шарпе, не знаю, а в Qt, например, запрещается работать с виджетами из другого потока. Но там есть сигналы и слоты - ими можно пользоваться. В шарпе это , вроде, делегатами называется
Записан

Dale
Блюзмен
Команда клуба

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

« Ответ #4 : 14-10-2010 11:06 » 

Я в подобных случаях поступаю так. Делаю структуру, в которой предусмотрены поля для всех параметров процесса, которые должны отображаться на "приборной панели" программы.

Все потоки пишут свои показания в эту структуру, а основной поток по таймеру раз в секунду перерисовывает форму на основании данных структуры. Просто и надежно.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Daniloff
Помогающий

ru
Offline Offline

« Ответ #5 : 14-10-2010 11:33 » 

я тоже про это подумал. Но таймер слишком ресурсоемким показался.
попробовал привязать отображение к событию окна - а окно-то и не меняется, любое событие появится только при определенном действии, тоже неинтересно...
Вот бы как-то намекнуть главному процессу... Плохо, что в C# основной цикл окна недоступен.

А в примерах нашел процесс, который порождает 2 потока, которые друг с другом перекидываются данными... А чтоб с основным - нету. Видимо, все же таймеры рулят Улыбаюсь
Записан
Dale
Блюзмен
Команда клуба

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

« Ответ #6 : 14-10-2010 11:51 » 

Если ежесекундная перерисовка окна требует много ресурсов, а данные меняются относительно редко, можно в эту структуру добавить флаг "данные обновлены". Каждый раз, обновляя данные, поток-писатель взводит этот флаг. Главный поток раз в секунду проверяет флаг, и если он взведен, перерисовывает окно и сбрасывает флаг. Проверка бита раз в секунду настолько мало напрягает систему, что можно не заморачиваться с событиями.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

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

« Ответ #7 : 14-10-2010 11:59 » 

Цитата: Daniloff
По OnClick запускается процедура, довольно долгоиграющая.
Пока крутится процедура, окно формы совершенно мертвое.
Что такое OnClick?

Это в приложении есть цикл приёма и обработки сообщений от Windows о действиях пользователя: движениях мышью, нажатию кнопок мыши и клавиш клавиатуры. Приложение запрашивает у операционной системы сообщения одно за другим и по очереди их обрабатывает. Если сообщений нет, приложение засыпает и ждёт, пока они появятся.

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

Естественно, так делать не стоит. Нужно завести отдельный поток, в котором что-то делается, и некие переменные, в которых хранится описание текущих действий. Основной поток приложения при этом остаётся свободным - он обрабатывает сообщения Windows или спит, если их нету. При потребности перерисовать окно основной поток может читать переменные, изменяемые в отдельном потоке, и по их содержимому строить изображение на форме. Если нужно обновлять информацию периодически, на форме заводится таймер, который "пинает" приложение через заданные интервалы времени. В Windows.Forms таймер построен так, что уведомление от него приходит в общую очередь сообщений операционной системы - т.е. обрабатывается наравне с прочими действиями пользователя.

Цитата: Daniloff
Но таймер слишком ресурсоемким показался.
Что это значит?

Цитата: Daniloff
Плохо, что в C# основной цикл окна недоступен.
У окна нет основного цикла, он есть только у приложения (ну или модального окна). Тем не менее в C# доступны для реализации и основной цикл приложения и все прочие WinAPI процедуры типа WndProc. Однако с их помощью ты ничего не сделаешь: твоя проблема решается либо вынесением длинного вычислительного процесса в отдельный поток, либо разбиением его на последовательность коротких кусочков и обработки очереди этих кусочков по таймеру. Во всех других случаях ты прерываешь получение от Windows сообщений, и окно "умирает".
« Последнее редактирование: 14-10-2010 12:00 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #8 : 14-10-2010 14:17 » 

До кучи... при обработке собития от таймера обновлять/перерисовывать форму можно при условии, что данные для отображение действительно изменились. А вот если они не изменились, то ничего не делать. Тогда фактически затраты ресурсов будут только на вызов этой проверки, что просто копейки
Записан

С уважением Lapulya
Daniloff
Помогающий

ru
Offline Offline

« Ответ #9 : 14-10-2010 14:43 » 

Спасибо, так наверно и сделаю.
Только у меня в течение секунды могут прийти 30 строк текста, которые нужно впихнуть в листбокс. А может и за 10 секунд ни одной не прийти. Придется в глобальных кучу переменных резервировать для переноса. Кстати, почему в С# нет оператора, противоположного "new" ?
Записан
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #10 : 14-10-2010 15:36 » 

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

delete не нужен там есть сборщик мусора, но нужно быть с неконтролируемыми тобой ресурсами (типа connection к БД и т.д.)
Записан

С уважением Lapulya
Dimka
Деятель
Команда клуба

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

« Ответ #11 : 14-10-2010 18:06 » 

Цитата: Daniloff
Только у меня в течение секунды могут прийти 30 строк текста, которые нужно впихнуть в листбокс.
Большой ListBox может подтормаживать. В таком случае приходящие строки нужно помещать в очередь (класс Queue) - это делается быстро вне зависимости от размера очереди, а в свободное время программа может их читать из очереди и добавлять. Естественно, для пользователя будет некоторая небольшая задержка в пределах нескольких секунд.

Цитата: Daniloff
Придется в глобальных кучу переменных резервировать для переноса.
Объясни, что это за "куча переменных"?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dale
Блюзмен
Команда клуба

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

« Ответ #12 : 14-10-2010 20:12 » 

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

Я в подобных случаях в качестве такого буфера обмена выделяю синглтон, который размещается в модели и собирает воедино все данные для представления. Что-то вроде "фасада". Зачастую его можно даже не синхронизировать между потоками читателя и писателя.

Кстати, почему в С# нет оператора, противоположного "new" ?

Для какой цели?
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #13 : 15-10-2010 01:48 » 

Dimka,
Цитата
Большой ListBox может подтормаживать. В таком случае приходящие строки нужно помещать в очередь (класс Queue) - это делается быстро вне зависимости от размера очереди
Чего то я не понял как ListBox (контрол на форме) связан с Queue (просто очередь)

Если вдруг (понятия не имею, как надо будет отображать данные) строк может быть реально много и нужен доступ не только к последнему добавленному, то проще свой список написать аналог std::list (тогда тоже быстро будет вне зависимости от размера списка), если Queue достаточно, то да, Димка прав надо его и юзать... Мда... хотя, тут очень многое зависит от режима работы, какие строки (длина), как часто приходят, как долго их надо хранить в модели (а не в форме) и т.д...
Записан

С уважением Lapulya
Dimka
Деятель
Команда клуба

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

« Ответ #14 : 15-10-2010 10:37 » 

Цитата: lapulya
Чего то я не понял как ListBox (контрол на форме) связан с Queue (просто очередь)
Как-как, стараниями программиста Улыбаюсь
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Daniloff
Помогающий

ru
Offline Offline

« Ответ #15 : 15-10-2010 11:57 » 

Queue - не пользовал, почитаю... Улыбаюсь
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #16 : 15-10-2010 13:56 » 

Чего там читать? Обычная очередь - с FIFO порядком работы.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines