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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите написать класс 
V
    Опции темы
Ch0bits
Дата 23.6.2006, 19:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Python Dev.
****


Профиль
Группа: Завсегдатай
Сообщений: 2124
Регистрация: 21.2.2005
Где: Казань

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



Нужно написать класс с асинхронными методами, пораждающими при работе асинхронные эвенты.  smile 
Например MyAsyncClass содержит AsyncMethod, который можно запускать многократно с разными параметрами без остановки. А эвенты не требуют invoke к потоку формы, чтобы в обработчике сразу можно было менять свойства компонентов формы, т.е. можно передавать ещё в параметры AsyncMethod ссылку на родительский поток формы или что-то в этом роде...  smile 

HELP!
 smile   

Это сообщение отредактировал(а) Ch0bits - 23.6.2006, 19:23
PM WWW   Вверх
mr.DUDA
Дата 23.6.2006, 22:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

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



Для вызова метод асинхронно через делегат - создаём экземпляр делегата и дёргаем BeginInvoke. Для того, чтобы по завершении Invoke выполнился наш "завершающий" метод - передаём в BeginInvoke делегат на свой метод (callback). Этот метод может делать что угодно, но обязан вызвать EndInvoke того же делегата. А с формой работать можно из любого потока, используя Control.Invoke и любой свой делегат.

З.Ы. проблемы могут начаться тогда, когда метод в другом потоке работает долго, и форма уже закрыта, а он обращается к её свойствам - вот это действительно проблемы, доложу я вам, и иногда даже приходится делать lock на Closing формы, чтобы не напороть исключений...  smile  


--------------------
user posted image
PM MAIL WWW   Вверх
stab
Дата 24.6.2006, 09:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

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



Цитата(mr.DUDA @  24.6.2006,  02:46 Найти цитируемый пост)
проблемы могут начаться тогда, когда метод в другом потоке работает долго, и форма уже закрыта, а он обращается к её свойствам - вот это действительно проблемы, доложу я вам, и иногда даже приходится делать lock на Closing формы, чтобы не напороть исключений


оффтоп немного:

у меня вообще такое желание, чтобы в языке сделали не lock, а unlock, т.е. чтобы все операции над объектом были поумолчанию потокобезопасными. как только поток начинает работать с объектом, сразу lock. а если уж взялся с потоками мучаться, вот тогда будь добр думай, где разрешать одновременный доступ. скорость выполения и первоначальной разработки конечно упадёт для многопоточных приложений, но и ошибок в дальнейшем на порядок меньше будет. такое моё мнение.  smile

Добавлено @ 09:29 
кстати, а чем вы себе такий юзербанеры делаете?  smile  


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
mr.DUDA
Дата 24.6.2006, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

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



Цитата(cully @  24.6.2006,  09:25 Найти цитируемый пост)
кстати, а чем вы себе такий юзербанеры делаете?  

оффтоп: поищи где-то в флейме или в обсуждении форума... или можешь ссылку на картинку у меня стянуть smile 


--------------------
user posted image
PM MAIL WWW   Вверх
Ch0bits
  Дата 29.6.2006, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Python Dev.
****


Профиль
Группа: Завсегдатай
Сообщений: 2124
Регистрация: 21.2.2005
Где: Казань

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



Задача немного изменилась: мне выгоднее использовать очередь, чем плодить кучу параллельных потоков.

Вот наконец дошли руки дописать:  smile  
Сам класс:
Код

    /// <summary>
    /// Параметры передаваемые потоку в точку входа
    /// </summary>
    public struct Parameters
    {
        #region Параметры описываем здесь!
        public int iSleep;
        #endregion
        
        public Parameters(int iSleep)
        {
            this.iSleep = iSleep;
        }
    }

    public delegate void __ChangeUI(AsyncQueueWorker Sender);

    public class AsyncQueueWorker : IDisposable
    {
        /// <summary>
        /// Ссылка на форму-родителя
        /// </summary>
        object thForm;

        /// <summary>
        /// Очередь потоков на выполнение
        /// </summary>
        Queue<Thread> ThreadsQueue=new Queue<Thread>();

        /// <summary>
        /// Очередь параметров потоков
        /// </summary>
        Queue<Parameters> ParamsQueue = new Queue<Parameters>();

        /// <summary>
        /// Конструктор
        /// </summary>
        /// <param name="thForm">Класс формы-родителя</param>
        public AsyncQueueWorker(object thForm)
        {
            this.thForm = thForm;
        }

        /// <summary>
        /// Постановка в очередь 
        /// </summary>
        /// <param name="Params">Параметры потока</param>
        public void AddAsyncOperation(Parameters P)
        {
            Thread T = new Thread(new ThreadStart(ThreadMain));

            // Если очередь пуста, то после вставки элемента его нужно запустить
            // Иначе метод потока сам проверяет наличие следующих элементов и запускает их
            lock (ThreadsQueue)
                lock (ParamsQueue)
                {
                    ThreadsQueue.Enqueue(T);
                    ParamsQueue.Enqueue(P);
                }
            if (ThreadsQueue.Count == 1) ThreadsQueue.Peek().Start();
        }

        /// <summary>
        /// Срабатывает после завершения работы элемента ThreadsQueue
        /// </summary>
        public event __ChangeUI OnElementalWorkCompleted;

        /// <summary>
        /// Срабатывает после полного завершения работы
        /// </summary>
        public event __ChangeUI OnWorkCompleted;

        /// <summary>
        /// Точка входа в поток
        /// </summary>
        void ThreadMain()
        {
            // Извлекаем параметры для текущего потока
            Parameters P = ParamsQueue.Dequeue();

            #region Работа производится здесь!

                Thread.Sleep(P.iSleep);
                MessageBox.Show(P.iSleep.ToString()); 

            #endregion

            // Дёргаем делегат
            (thForm as Control).BeginInvoke(new InvokeDelegate(InvokeCall));

            // После окончания работы поток удаляет себя из очереди
            ThreadsQueue.Dequeue();
            if (ThreadsQueue.Count!=0) ThreadsQueue.Peek().Start();
        }

        delegate void InvokeDelegate();
        void InvokeCall()
        {
            if (OnElementalWorkCompleted != null) OnElementalWorkCompleted(this);
            if ((OnWorkCompleted != null) && (this.QueueLength == 0)) OnWorkCompleted(this);
        }

        /// <summary>
        /// Возвращает количество элементов в очереди
        /// </summary>
        public int QueueLength
        {
            get { return ThreadsQueue.Count; }
        }

        /// <summary>
        /// Остановка всех оставшихся потоков
        /// </summary>
        public void Dispose()
        {
            while (ThreadsQueue.Count > 0) ThreadsQueue.Dequeue().Abort();
        }
    }


Пример использования:
Код

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

        AsyncQueueWorker AC;

        private void StartWork_Click(object sender, EventArgs e)
        {
            // Пример использования
            AC = new AsyncQueueWorker(this);

            AC.OnElementalWorkCompleted += new __ChangeUI(AC_ElementalWorkCompleted);
            AC.OnWorkCompleted += new __ChangeUI(AC_OnWorkCompleted);
           
            AC.AddAsyncOperation(new Parameters(3000));
            AC.AddAsyncOperation(new Parameters(2000));
            AC.AddAsyncOperation(new Parameters(1000));
        }

        void AC_OnWorkCompleted(AsyncQueueWorker Sender)
        {
            listBox1.Items.Add("Все операции завершены!");
        }

        void AC_ElementalWorkCompleted(AsyncQueueWorker Sender)
        {
            listBox1.Items.Add("Осталось выполнить "+Sender.QueueLength+" задач.");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (AC!=null) AC.Dispose();
        }
    }


Принимаю предложения по оптимизации...  smile  
PM WWW   Вверх
mr.DUDA
Дата 29.6.2006, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

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



Можно воспользоваться классом ThreadPool, потому что создание потока - операция относительно ресурсоёмкая. Тогда можно избавиться и от двух очередей (ThreadPool.QueueUserWorkItem позволяет поставить в очередь вызов с произв. параметрами - state). Тогда сократится количество lock-ов. Последнее замечание: если асинхронно вызывать у контрола (через BeginInvoke()) какую-л. операцию, есть шанс что контрол будет уничтожен в то время, как вызываемый метод ещё не доработал до конца - например, AC_ElementalWorkCompleted может пытаться добавить элемент в листбокс в то время, как форма уже закрылась и AC.Dispose() отработал. 


--------------------
user posted image
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

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


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

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




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


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

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