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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Многопоточное приложение, НЕ хочет работать 
:(
    Опции темы
SaS1
Дата 30.8.2007, 01:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Пишу такой код:

Код


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Threads
{
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void RunSecondThread()
        {
            for (int count = 0; count <= 20; count++)
            {
                listBox1.Items.Add(count);
                Thread.Sleep(50);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thrd = new Thread(new ThreadStart(this.RunSecondThread));
            thrd.Start();

        }

       

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            textBox1.Text = radioButton1.Text;
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            textBox1.Text = radioButton2.Text;
        }

        private void radioButton3_CheckedChanged(object sender, EventArgs e)
        {
            textBox1.Text = radioButton3.Text;
        }
    }


    
}




ОН компилируется, но во время выполнения выдаёт такую ошибку:

Cross-thread operation not valid: Control 'listBox1' accessed from a thread other than the thread it was created on.

на строке listBox1.Items.Add(count);

И я вот никак не пойму как сделать это правильно.
Помогите пожалуйста.
PM MAIL   Вверх
Mr_Smith
Дата 30.8.2007, 04:39 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Аксиома многопоточных приложений на .НЕТ, что "контролы можно менять только в контексте породившего их потока" поэтому компилятор на тебя и ругается
PM MAIL ICQ   Вверх
SpaceSpace
Дата 30.8.2007, 07:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Это можно обойти, если делать Invoke делегата функции которая изменяет ресурс в другом потоке

во превых,
поместим в отдельный метод  , который обращается к ресурсу

Код

 public void AsyncChange()

if (this.InvokeRequired)
{
ThreadStart updateStatus = new  ThreadStart(AsyncChange);
this.Invoke(updateStatus)
}
else
{
      // тут изменяеш  ресурс в другого потока

            for (int count = 0; count <= 20; count++)
            {
                listBox1.Items.Add(count);
                Thread.Sleep(50);
            }
}
}

Код

       private void button1_Click(object sender, EventArgs e)
        {
            Thread thrd = new Thread(new ThreadStart(AsyncChange()));
            thrd.Start();

        }


 


Это сообщение отредактировал(а) SpaceSpace - 30.8.2007, 07:33


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
mihryak
Дата 30.8.2007, 11:47 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



с делегатами посимпатичнее выглядит
Код

        private void button1_Click(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new EventHandler(button1_Click), sender, e);
            }
            else
            {
                ...
            }
        }

или (для произвольных сигнатур)
Код

        private delegate void MyHandler(object sender, EventArgs e);
        private void button1_Click(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MyHandler(button1_Click), sender, e);
            }
            else
            {
                ...
            }
        }

PM MAIL ICQ   Вверх
SpaceSpace
Дата 31.8.2007, 07:35 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



mihryak
молодец, повторил то же самое что и я!
продолжай в том же духе.

Код

ThreadStart updateStatus = new  ThreadStart(AsyncChange);


ThreadStart  - это и есть делегать на запуск непараметризированного потока


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
mihryak
Дата 31.8.2007, 09:13 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



SpaceSpace,  обрати внимание, что в первом случае не потребовалось писать дополнительный метод, т.к. делегат EventHandler<EventArgs> определён в MSDN, более того - в твоём коде теряется возможность не только обработать в большинстве случаев ненужные аргументы EventArgs, но и куда более полезный sender. А ведь помимо EventHandler<EventArgs> есть и море других "типовых" generic-обработчиков, где аргументы могуть быть более полезными.
Во втором случае вместо дополнительного метода потребовалось только объявить делегат с требуемой сигнатурой, и опять-таки - параметры не теряются, кода меньше, и он выглядит немного понятнее.
Да, кроме ThreadStart, есть и ParametrizedThreadStart, но и читаемостью кода та же штука. А сочетание компактности и читаемости - основные признаки хорошего кода, можно ведь и через emit код набросать, но кому это нужно? smile
ПС. больше оффтопить не буду, ответы автору даны.

Это сообщение отредактировал(а) mihryak - 31.8.2007, 09:17
PM MAIL ICQ   Вверх
SpaceSpace
Дата 31.8.2007, 09:26 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



mihryak
Я не считаю это оффтопом.
просто объясни 
Цитата

Во втором случае вместо дополнительного метода потребовалось


где содержится зерно логики.
Да, я согласен, что ты записал код без дополнительного метода,
согласись, что модернизировать мое предложение не составит труда - и оно также будет вызываться из
обработчика клика по кнопке.
Ты считаешь, что это логически и архитектурно обосновано?
Как мне кажется,
абсолютно нелогично делать
BeginInvoke(new EventHandler(button1_Click), sender, e);
т.к. это нарушает стройность и логику пиложения,
ведь после запуска нужного нам метода может потребоваться и другая логика,
именно поэтому Invoke был вынесен за пределы button1_Click,
это обосновано и оправдано , жду ваших корректив по этому утверждению

На счет  того что бывают разнве делегаты и свои и дженереки - с этим никто не спорил,
согласен, что для примера логичнее, круче и моднее использовать EventHandler<EventArgs>,



--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
mihryak
Дата 31.8.2007, 09:54 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Ок, давай тогда возьмём более реальный пример. Не думаю, что у кого-либо в здравом уме не для тестовых целей возникнет необходимость инвочить обработчик на нажатие кнопки (мышью в другом потоке не кликнешь, а вызывать этот обработчик из другого потока и есть то самое упомянутое нарушение стройности и глупая привязка логики к пользовательскому интерфейсу).
Также отбросим вариант, когда потоку просто нужно оповещать форму, что что-то где-то, так что действуй (опять-таки - либо тестовый набросок, либо трэд изменял не-UI свойства формы, и ей нужно только сказать, что эти свойства уже изменились и нужно перестроиться, а это тоже нелучшее решение).
Итак, остаётся один из главных вариантов - трэд через эвенты (например) посылает сообщения, содержащие какие-то нужные для бизнес-лигики, а потом и UI данные. В этом случае придётся использовать параметризированный ThreadStart, а у него простое объявление делегата однозначно выигрывает.
Таким образом, в обработчике эвента от треда нужно будет обрабатываться только эвент от треда, что к UI не имеет никакого отношения, и
Цитата(SpaceSpace @  31.8.2007,  10:26 Найти цитируемый пост)
и оно также будет вызываться из
обработчика клика по кнопке.

не будет уже актуальным, переписывать придётся только трэдовый обработчик.

UPD.
даже в упрощённой модели я бы не стал вызывать обработчик нажатия мыши по кнопе, вызывая некий аналог AsyncChange, только он скорее всего был бы параметризирован. В нём же бы и инвочил при необходимости.

Это сообщение отредактировал(а) mihryak - 31.8.2007, 10:05
PM MAIL ICQ   Вверх
SpaceSpace
Дата 31.8.2007, 10:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата

мышью в другом потоке не кликнешь, а вызывать этот обработчик из другого потока и есть то самое упомянутое нарушение стройности и глупая привязка логики к пользовательскому интерфейсу

Вот ты и признал, что твой пример ничем не лучше моего.
именно на это я и указывал.  smile 

На счет всего остального - соглашусь с тобой.
Хочу только заметить, что если инстанс одного (потока) 
лезет в свойства инстанса другого - т.к. является обработчиком какой либо логики и не имеет к нему отношения,
то этот поток, класически является бэкграундным и создан он исключительно для того(не трогаю повышение быстродействия в многопроцессорных системах) чтобы у пользователя
появилась иллюзия "одновременности" и "реалтаймовости".

Цитата

Таким образом, в обработчике эвента от треда нужно будет обрабатываться только эвент от треда, что к UI не имеет никакого отношения

жжешь  smile 

Не надо мне предьявлять того, на истинность чего я не посягал.

Надо уметь признавать свои ошибки и аргументировать свою точку зрения


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
mihryak
Дата 31.8.2007, 10:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



резюме такое - нефиг начинать спорить, взяв за основу надуманные или нежизненные примеры, спор выходит ни о чём smile
ну и напоследок тоже не удержусь от укольчика - в msdn async programming best practice всё-таки при InvoceRequired вместо создания и запуска  тредов используют таки инвоки делегатов :-Р
PM MAIL ICQ   Вверх
SpaceSpace
Дата 31.8.2007, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



согласен с тобой.
приятно пообщаться с умным человеком.
 smile 


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
SaS1
Дата 1.9.2007, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Ребята, спасибки за ответ. Я попробовала то, что вы предлогали и вроде ошибка не возникала. Но вот какая проблема применительно к моему примеру. Получается что сначала после нажатия бутона прога просто виснет на небольшое время, а потом сразу выводит все циферки и в то время, как она виснет, я не могу по радиобутонам нажимать. 
Простите за надуманный пример. В идеале у меня должно получиться приложение сервер, которое постоянно ждёт сообщений от клиентов, но при этом пользователь может с ним работать. Вот для этого мне и нужны были несколько потоков:(
Так что я до сих пор не понимаю как мне это так хитро сделать. Может поможете?
PM MAIL   Вверх
1stein
Дата 1.9.2007, 19:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



по-моему вам нужен BackgroundWorker. Вот здесь он на мой взгляд неплохо описан: http://www.rsdn.ru/article/dotnet/WinForms20.xml
PM MAIL   Вверх
SpaceSpace
Дата 3.9.2007, 07:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



SaS1
если у тебя будет сервер, то логичнее использовать пул потоков.
т.к. при создании нового потока затрачиваются большие  резурсы (скажем, 1000 циклов проца),
поэтому у тебя 
Цитата

прога просто виснет на небольшое время
 а если у тебя есть пул(который поставляется во фреймворке, созавать его не надо) - то при запуске приложения у тебя уже есть нескольго готовых к работе потоков, ты даеш им задания, после того как они его выполняют - снова переходят в состояние ожидания
Я думаю, что в твоем случае - это лучший выбор

Это сообщение отредактировал(а) SpaceSpace - 3.9.2007, 07:36


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

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


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

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


 




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


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

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