| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Разработка Windows Forms > проблема с многопоточностью |
| Автор: LifeMen 19.7.2013, 14:22 |
| Всем привет.Подскажите плз. Не разберусь с потоками... пытаюсь выполнить передачу файла на ftp в потоке(чтобы главное окно не зависло), но в итоге всё равно как будто в главном выполняется. код : using System.Threading; ................. public delegate void Showdeleg(); ................. FtpClient client = new FtpClient(); int TimeoutFTP = 30000; private void ConnectFTP () { ........... соединение } private void button3_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { try { Thread t = new Thread(Work); t.IsBackground = true; t.Start(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } void Work() { Showdeleg showProg = new Showdeleg(Go); this.Invoke(showProg); } void Go () { client.PutFile(TimeoutFTP * 1000, openFileDialog1.SafeFileName, openFileDialog1.FileName); } |
| Автор: jonie 19.7.2013, 16:53 | ||||
Надо сделать так: потокUI: запуская задачу (поток) поток задачи: производит закачку и в конце своей работы выполняет маршалинг (Invoke) чтобы уведомить UI поток об окончании своей работы. |
| Автор: LifeMen 19.7.2013, 19:47 | ||||||
Подскажи как в моём случае переделать. |
| Автор: dzaraev 19.7.2013, 21:33 | ||||||||
Очень просто, метод Work должен выглядеть вот так:
Дело вот в чем, вот этим вызовом
вы по сути сами направили свой доступ к FTP - в UI поток, как указал jonie. В начале метода Work вы уже находитесь в параллельном потоке, так зачем же вы возвращаетесь обратно в UI-поток? Для справки - http://msdn.microsoft.com/ru-ru/library/zyzhdc6b(v=vs.100).aspx посылает ваш вызов метода Go() в поток UI. В упрощенном виде это происходит так: В UI потоке работает бесконечный цикл, который на каждой итерации изымает из очереди сообщений ОС одно сообщение и обрабатывает его. Если сообщение содержит ссылку на код, который нужно выполнить (например ваш метод Go), то на этот код передаётся управление. Когда вы вызываете this.Invoke(showdeleg) вы по-сути отправляете в очередь ОС ссылку на метод Go() и "ждёте", когда UI-поток выполнит этот метод. Если бы вы вызвали this.BeginInvoke(showdeleg), то вы бы сделали то же самое, но не стали бы "ждать", пока UI поток выполнит метод Go(), а сразу бы вышли из Work(). Т.е. Invoke исполняет ваш делегат в UI-потоке синхронно, а BeginInvoke - асинхронно, по отношению к текущему потоку (в вашем случае - к потоку метода Work). Еще маленький совет - в .NET уже есть несколько существующих удобных делегатов, поэтому вы можете использовать их и не создавать свои. В частности, ваш public delegate void Showdeleg(); может быть спокойно удалён из кода и заменён стандартным делегатом Action:
Если после завершения асинхронного метода, вам нужно уведомить UI-поток (как предлагает jonie), то именно тогда вам нужно вызвать Invoke или BeginInvoke. При этом, если вам необязательно дожидаться окончания уведомляющего метода, вы можете использовать BeginInvoke, чтобы быстрее освободить поток Work(). Выглядеть будет примерно так:
Если ваш вопрос решён, пометьте его таковым, пожалуйста. |
| Автор: LifeMen 19.7.2013, 21:56 | ||||||||||
Спасибо вопрос решён |