Модераторы: gambit, Partizan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> проблема с многопоточностью, не получается реализовать поток 
V
    Опции темы
LifeMen
Дата 19.7.2013, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 19.7.2013

Репутация: нет
Всего: нет



Всем привет.Подскажите плз. Не разберусь с потоками... пытаюсь выполнить передачу файла на 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);
}
PM MAIL   Вверх
jonie
Дата 19.7.2013, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 5
Всего: 118



Цитата

Код

  this.Invoke(showProg);

тут у тебя происходит маршалинг из потока2 в UI поток. Для чего?
Надо сделать так:
потокUI: запуская задачу (поток)
поток задачи: производит закачку и в конце своей работы выполняет маршалинг (Invoke) чтобы уведомить UI поток об окончании своей работы.


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
LifeMen
Дата 19.7.2013, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 19.7.2013

Репутация: нет
Всего: нет



Цитата(jonie @ 19.7.2013,  16:53)
Цитата

Код

  this.Invoke(showProg);

тут у тебя происходит маршалинг из потока2 в UI поток. Для чего?
Надо сделать так:
потокUI: запуская задачу (поток)
поток задачи: производит закачку и в конце своей работы выполняет маршалинг (Invoke) чтобы уведомить UI поток об окончании своей работы.



Подскажи как в моём случае переделать.
PM MAIL   Вверх
dzaraev
Дата 19.7.2013, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 149
Регистрация: 12.1.2013

Репутация: нет
Всего: 1



Цитата(LifeMen @  19.7.2013,  19:47 Найти цитируемый пост)
как в моём случае переделать. 

Очень просто, метод Work должен выглядеть вот так:
Код

        void Work() {           
            Go();            
        }

Дело вот в чем, вот этим вызовом
Код

 this.Invoke(showProg);

вы по сути сами направили свой доступ к FTP - в UI поток, как указал jonie.
В начале метода Work вы уже находитесь в параллельном потоке, так зачем же вы возвращаетесь обратно в UI-поток?

Для справки - метод Control.Invoke() посылает ваш вызов метода 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:
Код

this.Invoke(new Action(Go));


Если после завершения асинхронного метода, вам нужно уведомить UI-поток (как предлагает jonie), то именно тогда вам нужно вызвать Invoke или BeginInvoke.
При этом, если вам необязательно дожидаться окончания уведомляющего метода, вы можете использовать BeginInvoke, чтобы быстрее освободить поток Work().
Выглядеть будет примерно так:
Код

        private void Work() {
            //здесь мы в новом параллельном потоке
            Go();
            this.BeginInvoke(new Action(ConnectionEstablished));
        }

        private void Go() {
           //мы всё еще в параллельном потоке
           client.PutFile(TimeoutFTP * 1000, openFileDialog1.SafeFileName, openFileDialog1.FileName);
        } 

        private void ConnectionEstablished() {
            //здесь мы уже снова в UI потоке
            textBox1.Text = "Connection established!";
        }

Если ваш вопрос решён, пометьте его таковым, пожалуйста. smile 

Это сообщение отредактировал(а) dzaraev - 19.7.2013, 21:37
--------------------
Если вопрос решён - помечайте тему.  
PM MAIL   Вверх
LifeMen
Дата 19.7.2013, 21:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 19.7.2013

Репутация: нет
Всего: нет



Цитата(dzaraev @ 19.7.2013,  21:33)
Цитата(LifeMen @  19.7.2013,  19:47 Найти цитируемый пост)
как в моём случае переделать. 

Очень просто, метод Work должен выглядеть вот так:
Код

        void Work() {           
            Go();            
        }

Дело вот в чем, вот этим вызовом
Код

 this.Invoke(showProg);

вы по сути сами направили свой доступ к FTP - в UI поток, как указал jonie.
В начале метода Work вы уже находитесь в параллельном потоке, так зачем же вы возвращаетесь обратно в UI-поток?

Для справки - метод Control.Invoke() посылает ваш вызов метода 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:
Код

this.Invoke(new Action(Go));


Если после завершения асинхронного метода, вам нужно уведомить UI-поток (как предлагает jonie), то именно тогда вам нужно вызвать Invoke или BeginInvoke.
При этом, если вам необязательно дожидаться окончания уведомляющего метода, вы можете использовать BeginInvoke, чтобы быстрее освободить поток Work().
Выглядеть будет примерно так:
Код

        private void Work() {
            //здесь мы в новом параллельном потоке
            Go();
            this.BeginInvoke(new Action(ConnectionEstablished));
        }

        private void Go() {
           //мы всё еще в параллельном потоке
           client.PutFile(TimeoutFTP * 1000, openFileDialog1.SafeFileName, openFileDialog1.FileName);
        } 

        private void ConnectionEstablished() {
            //здесь мы уже снова в UI потоке
            textBox1.Text = "Connection established!";
        }

Если ваш вопрос решён, пометьте его таковым, пожалуйста. smile

Спасибо вопрос решён smile
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Разработка Windows Forms | Следующая тема »


 




[ Время генерации скрипта: 0.0461 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.