![]() |
Модераторы: Partizan, gambit |
![]() ![]() ![]() |
|
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
При выборе элемента списка из комбобокса, вызывается LWS_UpdateInfo();. Она же вызывается, в OnIdle. Не знаю как, но когда я открываю список мышкой и не кликая перемещаю курсор с одного элемента списка на другой, срабатывает OnIdle. Как этого избежать? Т.е. Idle должен работать всегда, кроме момента, когда я работаю со списком. Как не пытался задействовать фокусы у списка и даже формы ничего не получается. Приложение либо снимается, либо работает так, как описано выше. |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Дело в том, что Idle вызывается каждый раз когда приложение простаивает (нет ничего в очереди сообщений). Поэтому, чтобы отделять ситуацию "приложение не выполняет действий" от ситуации "ждём реакции пользователя", нужно либо: 1) Не использовать Idle 2) В обработчике Idle проверять некий флаг, который ставить в true в каждом месте, где может возникнуть ожидание без действий со стороны пользователя (aka без добавления сообщений в очередь сообщений) -------------------- ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
2. Пытался такое сделать, но, в какой момент ставить флаг? На какиех двух событиях на комбобоксе это завязать?
Пробовал разное... |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Событие DropDown - генерится при открытии раскрывающегося списка. Событие DropDownClosed - при закрытии.
-------------------- ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
mr.DUDA, возможен еще и такой вариант, что список будет юзаться не раскрываясь через клаву или колесико мышки...
|
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Тогда ловим SelectedIndexChanged/SelectedItemChanged, но имхо это не то. Ведь юзер может долгое время просто ничего не делать - как это обрабатывать ? Забивать на Idle с момента получения фокуса комбобоксом ![]() Какую задачу вообще нужно решить ? Если необходимо выполнять действия в фоне, то вполне подойдёт отдельный поток (System.Threading.Thread). -------------------- ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
||||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Тогда отдельный поток - то что нужно. -------------------- ![]() |
|||
|
||||
ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
Пример:
|
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
А это не будет сильно грузить систему?
пошел покупать книжку Шилдта... |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Выставишь задержку в потоке, и будет занимать вообще 0% -------------------- ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Окей. Спасибо... Пойду разбираться.
Ресурсы, которые кушает поток будут меньше, чем аналогичная реализация алгоритма через Timer? |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Ну, в общем да; смотря какой таймер, кстати. Есть System.Windows.Forms.Timer, который работает через обычную очередь сообщений винды и WM_TIMER -- такой таймер будет пропускать тики до тех пор, пока есть необработанные сообщения в очереди, закинутые раньше чем тик; а есть System.Threading.Timer - он посылает свои события через ThreadPool. Что кстати не всегда подойдёт, т.к. в случае если обработка события таймера занимает бОльшее время, чем период таймера -- тогда события таймера будут накапливаться в очереди на обработку, вплоть до разбухания очереди до бесконечности. Поэтому, советую юзать класс Thread, с пом. которого запускать свой метод в отдельном потоке, и делать в этом методе любые действия, разделяя их паузой этак в 10-100 миллисекунд. З.Ы. кстати, если нужно работать с контролами на форме из отдельного потока -- то см. пример от ivashkanet, где стоит коммент " анонимный делегат, который поменяет значение Лабела"... -------------------- ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Не совсем понятно назначение этого анонимного делегата...
Реализовал через потоки. Работает. Попозже код положу. |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Ну, это для того чтобы можно было работать с виндошными контролами (окна, текстбоксы, листбокс, и т.п.) из не-GUI потоков. Обычно, если пытаешься например изменить текущий item в комбобоксе из другого потока -- генерируется exception. -------------------- ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Ну т.к. я вызываю в этом месте метод, который работает с контролами, то сделал без делегата...
|
|||
|
||||
ivashkanet |
|
||||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
По моему, в этой ситуации так же нужно использовать делегата. Ведь внутри вызываемого метода ты, как я понял, обращаешься к элементу юзер интерфейса. Попытаюсь объяснить почему именно так (один раз попробовал, но меня не поняли ![]() ![]() Главная проблемма потоков в том, что они работают одновременно один себе, второй себе, но могут использовать один и тот же объект (например тот же Лабел). Если они только читают информацию, то это все равно. Один прочитал, тут же второй -- никаких проблемм. Но вот если один из них вздумает изменить, тут начинаются проблеммы. Представим себе такую жизненную аналогию этой ситуации: У нас есть два ученика (два потока) и школьная доска (это объект с которым взаимодействуют эти потоки). На доске написано: "Мама мыла раму". Оба ученика с легкостью могут читать это сообщение, не заботясь о том, что кто-то так же читает это же сообщение. Но представьте себе ситуацию, когда первый ученик прочитал первую часть сообщения "Мама мыла", а второй тут же заменил сообщение на "Ехали медведи на велосипеде", о чем второй даже не догадывается. Что получится? Что-то типа "Мама мыла на велосипеде" --- бред? -- Да. Первый ученик будет в непонятнках (если он умный) или будет дальше использовать это предложение, считая что это нужное ему сообщение (если не совсем умный). Смысл, я надеюсь ясен ![]() Если вам интересно, как может такое случиться, что второй не заметит замену сообщения, то вас ждет приложение 1 Для разрешения этой ситуации придумано много методов: 1) Класс Threading.Monitor, который специально предназначен для разруливания таких ситуаций 2) конструкция (которая внутри себя используют именно Monitor).
3) Для UI (user interface) Майкрософт решила использовать (начиная со второй версии фрэймворка) еще один принцип: Изменять объекты UI может только один единственный поток --- UI-thread, который создается вместе с любой формой, и который обрабатывает системные сообщения. В свете нашей аналогии пусть это будет учитель. И только учитель может писать на доске. А для того, чтобы ученик мог изменять состояние доски используются просьбы к учителю: "Марь Иванна, напишите на доске "Ехали медведи на велосипеде", пожалуйста". Или в терминах .Net
Насколько это решает проблеммы? ИМХО, так себе. Проблему с одним учителем и одним учеником -- да, а вот если учеников будет два, то нет ![]() Но сейчас не об этом. С проблемой, ИМХО, закончили. Теперь о том, почему я считаю, что вызов метода внутри метода не решит проблемму: Что такое метод --- это всего лишь инструкция исполнителю. Этой инструкции совершенно все равно кто будет ей следовать. Поэтому если первый ученик (поток) будет следовать ей, а в середине увидит, что нужно взять другую инструкцию, то именно он будет ей следовать, а не кто-то другой. Вот такие вот дела ![]() Приложение 1 Немного теории распределения процессорного времени между потоками: Скажу сразу, что на полную достоверность я не претендую, но смысл будет передан верно, ИМХО. На однопроцессорной машине в один момент времени может выполняться только одна инструкция. Как же тогда достигается паралельность выполнения задач, спросите вы. Дело в том, что никакакая это не паралельность, а псевдопаралельность. Достигается это тем, что процессор постоянно используется разными процессами/потоками поочередно. Сначала первый, потом второй, третий, потом опять первый. В зависимости от приоретета потока. И промежутки времени настолько малы, что мы не можем заметить это переключение, для нас действия выполняются одновременно. И совершенно неизвесно, когда операцианная зистема заморозит выполняющийся поток и передаст управление новому. Это может быть в любой момент выполнения длинного действия (изменении надписи). Именно поэтому первый "ученик" может заснуть на середине прочтения надписи, а второй в это время изменить ее. P.S. Делегат -- это просто безопасная ссылка на метод (инструкцию). Ссылка на адрес в памяти, по которомы написана инструкция. |
||||||
|
|||||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Это я знал. Так, в принципе понятно, но... Получается так, что при выполнении двух потоков, один может заснуть, а второй создаст делегата и будет изменять контролы, в то время как первый до делегата не дошел. В таком случае проблема актуальна? Или псевдорапараллеливание устроено таким образом, что процесс может заснуть только унутри делегата, а не перед while'ом и т.п.? Хотя мне в это верится как-то с трудом. Сделал с делегатом... приложение подисает после энного кол-ва изменения выбранного элемента комбобокса ![]() |
|||
|
||||
ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
Это только для того, чтобы описываемая картина была более менее полна ![]() Увы да ![]() По мне, эта каша с "изменять объекты UI может только один единственный поток --- UI-thread" заварена только для того, чтобы обезопасить систему. Мало ли как можно повлиять на виндовые процессы, может даже на ядро системы через UI (это только догадки ![]() Самый главный принцип разруливания совмесной работы с двумя потоками заключается в использовании Threading.Monitor или его "обертки" lock. Если по простому, то никакой второй поток не может зайти внутрь lock-блока, если внутри уже есть другой. Он будет терпеливо ждать за пределами блока. Кроме того, если мы написали lock в двух местах (в двух разных частях программы) с одним и тем же аргументом (забыл как называется, что-то типа "объект синхронизации"), то если поток зашел внутрь в одном месте, то второй поток не сможет зайти внутрь блоков ни в первом, ни во втором месте. Пример с lock есть в ФАКе спасибо Доместиксу ![]()
Ну так под отладку его. Нажимаешь паузу и смотришь в каком месте застопорился главый поток формы ![]() Добавлено @ 20:06 P.S. Прошу прощение за смазанность первого сообщения. Не рассчитал время и не успел. Были дела. Попытаюсь дополнить. |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Thread.Sleep(100); распространяется на все процессы, которые запущены?
|
|||
|
||||
ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
||||
|
||||
Mal Hack |
|
||||||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Хм... Вот есть:
Тот, который _thread запущен и работает практически постоянно.
Второй запускается в нужный момент, что-то делает и отключается:
Во время выполнения второго потока, первый, который вызываем LWS_UpdateInfo как бы перестает работать, что не есть хорошо... Как это можно исправить? |
||||||
|
|||||||
ivashkanet |
|
||||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
Mal Hack, у тебя чуть чуть неправильный код.
Ты "доверил" UI потоку слишком много работы. Он должен только обновить контролы, а не ждать еще остановки сервиса. Ведь тогда он (UI поток) не сможет отвечать на запросы пользователя, т.е.
Предлагаю сделать так:
|
||||
|
|||||
ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
Кстати, так как метод LWS_UpdateInfo() полностью соответствует требованиям MethodInvoker-делегата (не имеет прараметров), то можно обойтись без анонимного делегата.
Т.е. так:
|
|||
|
||||
Mal Hack |
|
||||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
А ServiceControl в их число не входит? Т.е. грубо говоря, надо использовать делегата, когда пытаешься изменить свойства визуальных объектов? Так. Вроде бы с этим разобрался... Осталось вот что.
А очень надо. thrServiceBeginRun - фукция висит в потоке. После завершения работы, она должна поток удалить. Но этого не происходит. Устанвлено, что this.thrServiceEnd(); - не выполняется. |
||||
|
|||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
Проблему решил банально. this.thrServiceEnd(); заменяем на _threadStart = null;
|
|||
|
||||
ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
А можно увидеть код этой функции? Это выражение, по сути, только теряет ссылку на поток, после чего сборщик мусора его съест. Но вот когда это будет? Я бы внутри thrServiceEnd сделал _threadStart.Abort() , _threadStart.Join()б а только потом гасил ссылку
Ага. Mal Hack, ты попробуй удалить делегата. Если получишь Exception, то он был нужен, если нет то нет ![]() |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
||||
|
||||
ivashkanet |
|
|||
![]() Кодю потиху ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 3684 Регистрация: 23.2.2006 Где: Гомель, Беларусь Репутация: 47 Всего: 149 |
Да это не нужно делать ![]() У нас этот метод вызывается внутри нашего потока ![]() Именно поэтому аборты и джоины не нужны ![]() В принципе ничего не надо делать. Поток завершит работу по окончанииметода ![]() P.S. Mal Hack, ну и намудрил ты, гы. Нее, все нормально, но я, просто, не сразу понял твою логику. Не заметил, что thrServiceBeginRun --- это основной метод потока ![]() Это сообщение отредактировал(а) ivashkanet - 7.1.2007, 15:16 |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: нет Всего: 261 |
||||
|
||||
![]() ![]() ![]() |
Прежде чем создать тему, посмотрите сюда: | |
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |