Прямо праздник какой-то - каждый новый выпуск. Да ещё зимой обычно много праздников... Главное, чтобы у автора энтузиазм делиться своим опытом не пропадал. Я уверен - его жизненная карма обязана при этом становиться лучше. И его английский каким-то волшебным образом тоже.
Спасибо за урок. Познавательно. То что искал. Но осталось пара вопросов, хотя они м.б. были рассмотрены позднее. Многопоточность с Invoke. Ну как бы вопрос с содержимым кнопки "Отмена" отпал сам собой там и правда только _worker.Cancel(); Так вот: 1. Для чего в тексте форме после инициализации строки: button1.Click += button1_Click; button2.Click += button2_Click; ???? С ними нажатие на кнопку старт запускает сразу два потока. И у многих, как и у меня, возникла проблема с остановкой потока, он и прерывался и продолжал выполняться дальше. Решение Закомментировать или удалить эти строки. 2. Никто не пробовал закрыть форму (Главный "Красный" поток) до завершения синего, пока ProgressBar не заполниться? Вылетает законное исключение. Как отловить это исключение, точнее как остановить Синий вспомогательный поток при остановке главного Красного?
Просто отличный урок. Кстати, всем, кто найдет это видео уже спустя много лет после публикации (2014). Обратите внимание на комментарий Джона Скита (Aug 18 '15 at 11:22) к своему же ответу: stackoverflow.com/questions/13429129/task-vs-thread-differences?answertab=active#tab-top Т.е. сейчас (в наши дни) рекомендовано использование Task.Run.
Насчёт ситуации c прогресбаром в 16:16 : может это происходить из-за того, что к тому моменту когда вылезает окно операции по отрисовке( непосредственно рендерингу) ещё не успели выполниться до конца или не выполнился весь стек команд на отрисовку ?
Ролик отличный, жаль отсутствует ссылка на код. Есть немного неточностей: 17:00 Добавили строчку " progressBar.Value = progress + 1; ", но тогда в цикле при i = 100 условие i
Посмотрел видео. Начинающим будет довольно сложно понять. Недостаточно разжевано... Вот тут яснее - habrahabr.ru/post/232169/ Но за видео спасибо! Хорошая работа!
На WPF метод Invoke(action) следует заменить методом Dispatcher.Invoke(action) Проверку можно осуществить через вызов метода Dispatcher.CheckAccess() который проверяет есть ли у вызываемого метода доступ к потоку (или просто CheckAccess() == false) Таким образом если доступа нету вызываем метод Dispatcher.Invoke(Action callback): if(!CheckAccess()) Dispatcher.Invoke(action); else action();
Здравствуйте. У меня чёт не работает :) Вот как работает эта система: в классе есть функция Work(), которая вызывает Action "ProgressChanged" с параметром, который (Action) в свою очередь связан c функцией worker_ProcessChanged, производящую манипуляции с прогресс баром. И вызывая функцию класса Work() вызывается worker_ProcessChanged через Action. Я сделал так же: я создал функцию OpNLoad, принимающая на вход OpenFileDialog (он объявлен глобально и определяется по нажатию кнопки). Затем создал Action с тем же типом принимаемого параметра (OpenFileDialog) tryOpen. Далее в нажатии кнопки до определения потока присвоил tryOpen += OpNLoad. Также создал ещё функцию StartLoad, вызывающую Action tryOpen с параметром OpenFileDialog, определённый при нажатии кнопки, и передаю эту функцию (StartLoad) в поток. Структурно всё также, как в видео (на 11:35), функция вызывает Action, связанный с другой функцией, и первая функция передаётся в поток, но всё равно ругается на то, что идёт манипуляция с элементом, созданном в другом потоке (ругается всё также на прогресс бар). UPD: посмотрел дальше и объявил новый Action, который в теле выполняет действия, затем вызвал это действие через Invoke. На прогресс бар уже не ругается и всё загружает, но всё равно не могу двигать формой в процессе загрузки
Здравствуйте, у меня такая проблема. Когда я закрываю форму, (попробовав в закрытии вызвать метод отмены), то выбрасывается исключение - Доступ к ликвидированному объекту невозможен. Имя объекта: "Form1"." Как можно с этим бороться? Заранее спасибо. Пробовал окружать Invoke условием if (this.IsDisposed == false) { this.Invoke(action); } Но почему-то не срабатывает
Поясните, пожалуйста, почему в синхронном коде у нас зависает форма при работе приложения, а при использовании SynchronizationContext не зависает. Ведь в обоих случаях мы используем один поток (красный). А еще не понятно зачем нужна проверка InvokeRequired. Что происходит если форма решит что не надо делать Invoke? Мы никогда не попадем в наш метод, но мы же хотим туда попасть!
+Yuriy Smirnov 1. При синхронном коде приложение занято выполнением рабочей операции, и из-за этого ему "некогда" реагировать на действия пользователя. Отсюда зависание формы. 2. Обратите внимание: если Invoke не нужен, то операция вызывается, как обычно, не через Invoke. Т.е. значение прогрессбара в любом сценарии будет увеличено.
+Программирование - это просто, спасибо за ответы. Вот еще пара вопросов, если можно. 1. Правильно ли я понимаю, что первый и главный поток это SynchronizationContext который сам запускает поток (второй) для WinForms. Мы передаем наши рабочие операции в главный поток и они выполняются как бы "над потоком" формы. Иначе не понятно за счет чего используя SynchronizationContext мы избегаем блокировки. Если второго потока нет, то программа выполняется линейно. Доходит до рабочей операции и должна "повесить" форму. 2. Не заметил else, извиняюсь, сглупил. Но так ведь еще хуже: операция вызывается не через invoke, значит должно произойти перекрещивание потоков?!
+Yuriy Smirnov 1. Главный поток всегда один. Он циклически опрашивает форму, но внутри цикла так же выполняется и рабочий код. Если рабочий код длительный, то естественно что форма "замораживается", потому что главный поток занят выполнением рабочей задачи и опрос формы останавливается. SynchronizationContext - это по сути список делегатов, который тоже находится в этом цикле опроса. Если мы вынесем долгую рабочую операцию в другой поток, а из этого другого потока будем помещать делегаты в этот специальный список, то алгоритм главного потока будет примерно таким: а) опросить формы (реакция на действия пользователя, изменение внешнего вида) б) выполнить короткий рабочий код, если он есть (длинный то мы вынесли в другой поток) в) выполнить делегаты в списке SynchronizationContext (и тут-то происходит изменение прогресс-бара, появление сообщений об окончании работы и т. д.) 2. Если invoke не нужен, значит, поток один и никакого перекрещивания не происходит )
А как можно передать сам контрол в обработку метода из под другого потока? например метод public void AddRowsDgw(DataGridView Dgw). У меня не получилось это сделать, но сделал некий велик, внутри потока создаю такой же контрол и потом при выходе метода из копии контрола выдаю данные и свойства во внешний контрол не из потока. Может как нибудь по другому можно обойтись ? )
Я не понимаю почему вы на 19:18 пишите this.InvokeEx(action); это же эквивалентно Form1.InvokeEx(action); если я не ошибаюсь. Нам же нужно обращаться к статическому методу класса ControlHelp, тобиш ControlHelp.InvokeEx(this, action);
Код в примере постоянно эволюционирует - показываются различные в том числе и ошибочные варианты, поэтому конкретного кода для урока здесь иногда не бывает... И в этом уроке почти всё показано, кроме создания объекта _context: SynchronizationContext _context = new SynchronizationContext(); в форме.
Defazze Не знаю. Может у меня код другой, _context без типа данных - это ведь просто идентификатор. У меня он подсвечивался красным, создал объект с одноименной ссылкой - всё скомпилировалось... Не важно.
Я один заметил, что перед тем как вызывать событие, его нужно проверить на null? Т.е. что у нас есть подписчики. Т.к. если их нет а мы вызовем без проверки, будет исключение. У автора ролика я этого не увидел.
Что за пример для задротов? Нахрена такие сложные примеры, нахрена этот класс в обучении, нахрена усложнять простое. Типичное неадекватное обучение как в школе, интерес пропадает сразу
Прямо праздник какой-то - каждый новый выпуск. Да ещё зимой обычно много праздников... Главное, чтобы у автора энтузиазм делиться своим опытом не пропадал. Я уверен - его жизненная карма обязана при этом становиться лучше. И его английский каким-то волшебным образом тоже.
7:31 Thread
12:41 Invoke
19:31 SynchronizationContext
Это лучший видеоурок по потокам.
Спасибо огромное! Целый день парился. А тут все по полочкам.
отличный канал, организаторы уроков молодцы! искал именно в подробнастях. Спасибо!
Спасибо за урок. Познавательно. То что искал. Но осталось пара вопросов, хотя они м.б. были рассмотрены позднее.
Многопоточность с Invoke.
Ну как бы вопрос с содержимым кнопки "Отмена" отпал сам собой там и правда только _worker.Cancel();
Так вот:
1. Для чего в тексте форме после инициализации строки:
button1.Click += button1_Click;
button2.Click += button2_Click;
????
С ними нажатие на кнопку старт запускает сразу два потока. И у многих, как и у меня, возникла проблема с остановкой потока, он и прерывался и продолжал выполняться дальше. Решение Закомментировать или удалить эти строки.
2. Никто не пробовал закрыть форму (Главный "Красный" поток) до завершения синего, пока ProgressBar не заполниться? Вылетает законное исключение.
Как отловить это исключение, точнее как остановить Синий вспомогательный поток при остановке главного Красного?
Очень хорошо - лаконично, ничего лишнего!
С первого раза понял про многопоточность. Браво автор
Спасибо за такие каналы как ваш! Очень полезная информация!
Хорошее описание, все четко и по делу!
Просто отличный урок.
Кстати, всем, кто найдет это видео уже спустя много лет после публикации (2014). Обратите внимание на комментарий Джона Скита (Aug 18 '15 at 11:22) к своему же ответу: stackoverflow.com/questions/13429129/task-vs-thread-differences?answertab=active#tab-top
Т.е. сейчас (в наши дни) рекомендовано использование Task.Run.
Спустя 6 лет
Как же долго я искал именно такой урок. Спасибо вам большое!!!
Спасибо, очень подробно!
Отличный урок. Спасибо.
Спасибо, понравилось!🙂
Большое спасибо за урок!
На моей предыдущей работе все разработчики тоже говорили "шедУлер". Так по-родному звучит ))))
Браво! Спасибо за урок!
Вспомнился фильм "Охотники за привидениями".) "Нельзя скрещивать потоки!" =)
Очень круто! Большое спасибо!
именно то что я искал, спасибо большое !
Круто. Tasks бы с async\await действительно не помешал)
Будет в следующей части )
Очень доступно! Спасибо
Спасибо, отличный урок.
вот щас бы про MVC посмотреть)
хорошиее видео подробное у вас получаеться все понятно
Спасибо!
ASP.NET MVC это вообще интересная тема. так что буду ждать
Defazze, кол-во просмотров растет. В след видео вставь номер кошелька. С мира по нитке, а тебе приятно.
Большой вопрос: нажимая кнопку стоп messageBox выводится, а вот progressBar не останавливается и доходит до конца. Почему так?
Насчёт ситуации c прогресбаром в 16:16 : может это происходить из-за того, что к тому моменту когда вылезает окно операции по отрисовке( непосредственно рендерингу) ещё не успели выполниться до конца или не выполнился весь стек команд на отрисовку ?
Ролик отличный, жаль отсутствует ссылка на код. Есть немного неточностей:
17:00 Добавили строчку " progressBar.Value = progress + 1; ",
но тогда в цикле при i = 100 условие i
Вряд ли. Если что и будет, то ASP.NET MVC
+Defazze Так где же ASP.NET? У вас очень хорошие уроки, с удовольствием смотрел бы серию асп.нет мвс.
может вернетесь с курсом по asp.net Core
Оператор лилии Брик
Посмотрел видео. Начинающим будет довольно сложно понять. Недостаточно разжевано...
Вот тут яснее - habrahabr.ru/post/232169/
Но за видео спасибо! Хорошая работа!
Супер
На WPF метод Invoke(action) следует заменить методом Dispatcher.Invoke(action)
Проверку можно осуществить через вызов метода Dispatcher.CheckAccess() который проверяет есть ли у вызываемого метода доступ к потоку (или просто CheckAccess() == false)
Таким образом если доступа нету вызываем метод Dispatcher.Invoke(Action callback):
if(!CheckAccess())
Dispatcher.Invoke(action);
else
action();
Здравствуйте. У меня чёт не работает :)
Вот как работает эта система: в классе есть функция Work(), которая вызывает Action "ProgressChanged" с параметром, который (Action) в свою очередь связан c функцией worker_ProcessChanged, производящую манипуляции с прогресс баром. И вызывая функцию класса Work() вызывается worker_ProcessChanged через Action.
Я сделал так же:
я создал функцию OpNLoad, принимающая на вход OpenFileDialog (он объявлен глобально и определяется по нажатию кнопки). Затем создал Action с тем же типом принимаемого параметра (OpenFileDialog) tryOpen. Далее в нажатии кнопки до определения потока присвоил tryOpen += OpNLoad. Также создал ещё функцию StartLoad, вызывающую Action tryOpen с параметром OpenFileDialog, определённый при нажатии кнопки, и передаю эту функцию (StartLoad) в поток.
Структурно всё также, как в видео (на 11:35), функция вызывает Action, связанный с другой функцией, и первая функция передаётся в поток, но всё равно ругается на то, что идёт манипуляция с элементом, созданном в другом потоке (ругается всё также на прогресс бар).
UPD: посмотрел дальше и объявил новый Action, который в теле выполняет действия, затем вызвал это действие через Invoke. На прогресс бар уже не ругается и всё загружает, но всё равно не могу двигать формой в процессе загрузки
Почему-то после остановки процесса он продолжается, хоть и выходит окно с ошибкой. Из-за чего может быть?
А будет ли рассмотрен паттерн MVVM, как это было с MVP?
А какой код в кнопке Stop? (На видео не показано).
UPDATE: Разобрался, там _worker.Cancel();
у меня все равно не работает , progressBar не останавливается (((
Где бы скачать исходник этого урока?
молодец
про кнопку стоп то не рассказали ))
то, что надо.
спасибо, Бро :)
Скажите пожалуйста, будет ли разсмотрен вопрос отладки многопоточных приложений?
не планировал.
@@Defazze не написали код обработчика события нажатия второй кнопки
Суппер, +++
Почему не показали код в баттоне Стоп? Мне лично любопытно как остановить поток.
private void butStop_Click(object sender, EventArgs e)
{
if (_worker != null)
_worker.Cancell();
}
Здравствуйте, у меня такая проблема. Когда я закрываю форму, (попробовав в закрытии вызвать метод отмены), то выбрасывается исключение - Доступ к ликвидированному объекту невозможен.
Имя объекта: "Form1"."
Как можно с этим бороться? Заранее спасибо. Пробовал окружать Invoke условием if (this.IsDisposed == false)
{
this.Invoke(action);
} Но почему-то не срабатывает
Ничего не понял, но очень интересно)
спасибо )
Поясните, пожалуйста, почему в синхронном коде у нас зависает форма при работе приложения, а при использовании SynchronizationContext не зависает. Ведь в обоих случаях мы используем один поток (красный).
А еще не понятно зачем нужна проверка InvokeRequired. Что происходит если форма решит что не надо делать Invoke? Мы никогда не попадем в наш метод, но мы же хотим туда попасть!
+Yuriy Smirnov
1. При синхронном коде приложение занято выполнением рабочей операции, и из-за этого ему "некогда" реагировать на действия пользователя. Отсюда зависание формы.
2. Обратите внимание: если Invoke не нужен, то операция вызывается, как обычно, не через Invoke. Т.е. значение прогрессбара в любом сценарии будет увеличено.
+Программирование - это просто, спасибо за ответы. Вот еще пара вопросов, если можно.
1. Правильно ли я понимаю, что первый и главный поток это SynchronizationContext который сам запускает поток (второй) для WinForms. Мы передаем наши рабочие операции в главный поток и они выполняются как бы "над потоком" формы.
Иначе не понятно за счет чего используя SynchronizationContext мы избегаем блокировки.
Если второго потока нет, то программа выполняется линейно. Доходит до рабочей
операции и должна "повесить" форму.
2. Не заметил else, извиняюсь, сглупил. Но так ведь еще хуже: операция вызывается не через invoke, значит должно произойти перекрещивание потоков?!
+Yuriy Smirnov
1. Главный поток всегда один. Он циклически опрашивает форму, но внутри цикла так же выполняется и рабочий код. Если рабочий код длительный, то естественно что форма "замораживается", потому что главный поток занят выполнением рабочей задачи и опрос формы останавливается. SynchronizationContext - это по сути список делегатов, который тоже находится в этом цикле опроса. Если мы вынесем долгую рабочую операцию в другой поток, а из этого другого потока будем помещать делегаты в этот специальный список, то алгоритм главного потока будет примерно таким:
а) опросить формы (реакция на действия пользователя, изменение внешнего вида)
б) выполнить короткий рабочий код, если он есть (длинный то мы вынесли в другой поток)
в) выполнить делегаты в списке SynchronizationContext (и тут-то происходит изменение прогресс-бара, появление сообщений об окончании работы и т. д.)
2. Если invoke не нужен, значит, поток один и никакого перекрещивания не происходит )
"As soon as you type new Thread(), it’s over, your project already has legacy code" - Concurrency in C# Cookbook, By Stephen Cleary.
Можно проще:
Invoke((Action)(() => { /* Действия в главном потоке */ }));
а я на есемблере всего 30 строк вся многопоточность ))) занимает
А как можно передать сам контрол в обработку метода из под другого потока? например метод public void AddRowsDgw(DataGridView Dgw). У меня не получилось это сделать, но сделал некий велик, внутри потока создаю такой же контрол и потом при выходе метода из копии контрола выдаю данные и свойства во внешний контрол не из потока. Может как нибудь по другому можно обойтись ? )
Не надо создавать контролы не в основном потоке. Это оборачивается гигантским количеством проблем.
почему то у меня ProgrerssChanged выдает null reference exception
Лайк.
Когда будут новые уроки 7
Сергей Коваль Скоро
По мне так вариант с invoke - очень стрёмное решение с т.з. архитектуры приложения
Я не понимаю почему вы на 19:18 пишите this.InvokeEx(action); это же эквивалентно Form1.InvokeEx(action); если я не ошибаюсь. Нам же нужно обращаться к статическому методу класса ControlHelp, тобиш ControlHelp.InvokeEx(this, action);
Потому, что это расширение. Обратите внимание на урок "Три Кита". Где-то во второй половине урока автор расказывает о преимуществе даного подхода.
Станьте моим учителем) по с#
Напоминает свёртку в линейной алгебре. (x, f) => f(x), где x in L, f in L*.
извините, а неужели сложно выложить и исходники?
Ребят как называется библиотека xakep.ru/2010/08/10/52926/ ?
Плиз выложите на дробокс или гугл драйв примеры.
Код в примере постоянно эволюционирует - показываются различные в том числе и ошибочные варианты, поэтому конкретного кода для урока здесь иногда не бывает... И в этом уроке почти всё показано, кроме создания объекта _context: SynchronizationContext _context = new SynchronizationContext(); в форме.
София Солнцева как это не показано, 21:33, обработчик MainForm_Load )
Defazze Не знаю. Может у меня код другой, _context без типа данных - это ведь просто идентификатор. У меня он подсвечивался красным, создал объект с одноименной ссылкой - всё скомпилировалось... Не важно.
Автор жлобяра, исходник зажал!
люди, код бросьте в коомент, пожалуйста!
У меня не возникло исключения после создания потока))
Я один потерял инициализацию _context?
Не один
срэд
а что в C шарп многопоточность есть ? интерестно а в бейсике есть ?
Дослушал до места "брик".
Автор неужели так сложно выложить исходник?
Отличный урок. Спасибо. Но произношение у автора английского просто ппц. После того как он скедъюлер назвал шедулером я чуть не умер))
AbelardoTV шедьюлер - английский вариант, скедьюлер - американский (или наоборот)
Я один заметил, что перед тем как вызывать событие, его нужно проверить на null? Т.е. что у нас есть подписчики.
Т.к. если их нет а мы вызовем без проверки, будет исключение. У автора ролика я этого не увидел.
Ни_я непонятно. !!!!
Что за пример для задротов? Нахрена такие сложные примеры, нахрена этот класс в обучении, нахрена усложнять простое. Типичное неадекватное обучение как в школе, интерес пропадает сразу
Руслан Баскунов прост уроки не для аутов, что и сказано в описании канала.
А чо там сложного ?? пара эвентов если смутила так это база без её знания смысл смотреть это видео стремиться к нулю
форму создал, а дальше переписывать с видео не стал, автор жлобяра, мог бы и поделится исходником!
молодец