Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: В очередь! C#  (Прочитано 11480 раз)
0 Пользователей и 1 Гость смотрят эту тему.
MasterMan342
Участник

ru
Offline Offline
Пол: Мужской

« : 18-03-2012 14:05 » 

Добрый вечер! в общем проблема такая:
В программе создается N кол-во потоков (ну допустим 2), в разное время.
Из каждого, в определенный промежуток времени должно вызываться диалоговое окно (если оно еще не открыто), и передаваться данные - например строка с именем вызываемого потока...

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

Грубо говоря все одноименные действия потоков должны выполнятся в 1 окне, а не в нескольких. И выполнение методов из которых произошел вызов должны временно приостанавливаться, до возвращения им управления...

Надеюсь все предельно ясно объяснено  Краснею
Как такое можно реализовать???
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 18-03-2012 14:38 » 

Надеюсь все предельно ясно объяснено  Краснею

Не надейся. Тебе не понятно, а другим - тем более. Попробуй объяснить задачу, а не выдавать обрывки мыслей.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 18-03-2012 16:27 » 

Для работы окна нужен отдельный поток. Этот поток может спать и ждать события (AutoResetEvent), которое устанавливает каждый рабочий поток после помещения данных в очередь. После установки события поток окна просыпается и открывает модальное окно, которое не закрывается, пока очередь не опустошится. После закрытия окна поток в цикле возвращается в спящее состояние к ожиданию события.

Очередь (Queue), естественно, должна быть синхронизирована на операции постановки в очередь, извлечения из очереди и проверки на пустоту. Для этого можно создать собственный класс-обёртку и внутри методов использовать конструкцию lock(this). Установку вышеупомянутого события для потока окна можно поручить обёртке в методе постановки очередного запроса в очередь.

Чтобы рабочие потоки ждали окончания обработки, запросы, которые поступают в очередь, нужно упаковать в структуру вместе с событиями (либо ManualResetEvent, либо AutoResetEvent). Флаг события должен быть изначально сброшен. Когда рабочий поток обращается к классу-обёртке очереди с просьбой поместить данные на обработку, обёртка создаёт эту структуру, в которую помещает данные и новое созданное событие, затем всю структуру ставит в очередь. Далее возвращает вызывающему потоку объект события. Вызывающий поток, получив событие, тут же становится на его ожидание. Поток окна, извлекая из очереди структуры, обрабатывает данные, а в конце обработки очередного запроса устанавливает событие из текущей структуры. Это разбудит именно тот ожидающий рабочий поток, который послал именно этот запрос, и позволит ему продолжить работу.
« Последнее редактирование: 18-03-2012 16:31 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
MasterMan342
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 18-03-2012 16:30 » 

Надеюсь все предельно ясно объяснено  Краснею

Не надейся. Тебе не понятно, а другим - тем более. Попробуй объяснить задачу, а не выдавать обрывки мыслей.

мне нужно сделать 1 окно в котором будут обрабатываться данные из нескольких потоков поочередно, в порядке добавления. т.е. при вызове одного и того-же экземпляра этого окна, из разных мест, в одно и то-же время - вызовы обрабатывались в порядке возникновения, и по очереди после завершения предыдущего - в 1 окне.

Например: из метода 1 потока поступил вызов диалогового окна(ДО) в котором пользователь вводит в 2 поля значения X и Y , нажимает на кнопку - после того как произвелись действия должен вернуть результат в переменную, и продолжить выполение метода из которого была вызвана. НО пока пользователь вводит данные, ДО было вызвано из другого потока (этот же экземпляр). Нужно что-бы данные переданные из 2 потока в это окно начали обрабатываться после завершения обработки данных первого...

т.е. пользователь жмет кнопку - результат возвращается в первый поток, в этом-же окне обрабатываются данные 2 потока и результат возвращается во 2 поток. Если более вызовов окна не поступало - оно закрывается.

Добавлено через 5 минут и 8 секунд:
Для работы окна нужен отдельный поток. Этот поток может спать и ждать события (AutoResetEvent), которое устанавливает каждый рабочий поток после помещения данных в очередь. После установки события поток окна просыпается и открывает модальное окно, которое не закрывается, пока очередь не опустошится. После закрытия окна поток в цикле возвращается в спящее состояние к ожиданию события.

Очередь (Queue), естественно, должна быть синхронизирована на операции постановки в очередь, извлечения из очереди и проверки на пустоту. Для этого можно создать собственный класс-обёртку и внутри методов использовать конструкцию lock(this). Установку вышеупомянутого события для потока окна можно поручить обёртке в методе постановки очередного запроса в очередь.

Чтобы рабочие потоки ждали окончания обработки, запросы, которые поступают в очередь, нужно упаковать в структуру вместе с событиями (либо ManualResetEvent, либо AutoResetEvent). Флаг события должен быть изначально сброшен. Когда рабочий поток обращается к классу-обёртке очереди с просьбой поместить данные на обработку, обёртка создаёт эту структуру, в которую помещает данные и новое созданное событие, затем всю структуру ставит в очередь. Далее возвращает вызывающему потоку объект события. Вызывающий поток, получив событие, тут же становится на его ожидание. Поток окна, извлекая из очереди структуры, обрабатывает данные, а в конце обработки очередного запроса устанавливает событие из текущей структуры. Это разбудит именно тот ожидающий рабочий поток, который послал именно этот запрос, и позволит ему продолжить работу.

Спасибо за совет) но можно пример? я еще только пол года изучаю C# и не очень хорошо все это понимаю...
« Последнее редактирование: 18-03-2012 16:35 от MasterMan342 » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 18-03-2012 17:34 » 

Код: (C#)
using System;
using System.Collections.Generic;
using System.Threading;

namespace Test
{
    class Request
    {
        public static object Call(object source)
        {
            Request request = new Request();
            request.ready = new AutoResetEvent(false);
            request.source = source;
            request.result = null;
            MyQueue.Send(request);
            request.ready.WaitOne();
            return request.result;
        }

        private object source;
        private object result;
        private AutoResetEvent ready;

        public object GetSource()
        {
            return this.source;
        }

        public void SetResult(object result)
        {
            this.result = result;
            this.ready.Set();
        }

    }

    class MyQueue
    {
        private static Queue<Request> queue;
        private static AutoResetEvent notEmpty;

        static MyQueue()
        {
            MyQueue.queue = new Queue<Request>();
            MyQueue.notEmpty = new AutoResetEvent(false);
        }

        public static void Send(Request request)
        {
            lock (MyQueue.queue)
            {
                MyQueue.queue.Enqueue(request);
            }
            MyQueue.notEmpty.Set();
        }

        public static Request Receive()
        {
            for (; ; )
            {
                Request result = null;
                lock (MyQueue.queue)
                {
                    if (MyQueue.queue.Count > 0)
                    {
                        result = MyQueue.queue.Dequeue();
                    }
                }
                if (result != null)
                {
                    return result;
                }
                else
                {
                    MyQueue.notEmpty.WaitOne();
                }
            }
        }
    }

    class Program
    {
        static Random random;

        public static void RandomSleep()
        {
            int sleepTime = 0;
            lock (Program.random)
            {
                sleepTime = random.Next(5000);
            }
            Thread.Sleep(sleepTime);
        }

        static void WorkMain(object parameter)
        {
            int threadNumber = Convert.ToInt32(parameter);
            Console.WriteLine("Рабочий поток {0} начал работу.", threadNumber);
            try
            {
                for (; ; )
                {
                    Console.WriteLine("Рабочий поток {0} работает.", threadNumber);
                    Program.RandomSleep();
                    object source = new object();
                    Console.WriteLine("Рабочий поток {0} посылает данные на обработку и ждёт результата.", threadNumber);
                    object result = Request.Call(source);
                    Console.WriteLine("Рабочий поток {0} получил результат обработки данных.", threadNumber);
                }
            }
            catch
            {
                Console.WriteLine("Рабочий поток {0} прервал работу.", threadNumber);
            }
            Console.WriteLine("Рабочий поток {0} закончил работу.", threadNumber);
        }

        static void DialogMain()
        {
            Console.WriteLine("Поток окна начал работу.");
            try
            {
                for (; ; )
                {
                    Console.WriteLine("Поток окна ожидает запроса.");
                    Request request = MyQueue.Receive();
                    Console.WriteLine("Поток окна получил запрос и обрабатывает его.");
                    Program.RandomSleep();
                    Console.WriteLine("Поток окна записывает результат обработки запроса.");
                    request.SetResult(new object());
                }
            }
            catch
            {
                Console.WriteLine("Поток окна прервал работу.");
            }
            Console.WriteLine("Поток окна закончил работу.");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Главный поток начал работу. Запуск дочерних потоков.");
            Program.random = new Random();
            Thread thread;
            for (int i = 1; i <= 2; ++i)
            {
                thread = new Thread(new ParameterizedThreadStart(WorkMain));
                thread.IsBackground = true;
                thread.Start(i);
            }
            thread = new Thread(new ThreadStart(DialogMain));
            thread.IsBackground = true;
            thread.Start();
            Console.WriteLine("Главный поток ждёт нажатия любой клавиши для завершения работы.");
            Console.ReadKey();
            Console.WriteLine("Главный поток завершил работу.");
        }
    }
}
Пример консольный, иллюстрирующий архитектуру решения. Окна, реальные данные - это всё сам приделывай.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
MasterMan342
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 19-03-2012 05:21 » 

Код: (C#)
using System;
using System.Collections.Generic;
using System.Threading;

namespace Test
{
    class Request
    {
        public static object Call(object source)
        {
            Request request = new Request();
            request.ready = new AutoResetEvent(false);
            request.source = source;
            request.result = null;
            MyQueue.Send(request);
            request.ready.WaitOne();
            return request.result;
        }

        private object source;
        private object result;
        private AutoResetEvent ready;

        public object GetSource()
        {
            return this.source;
        }

        public void SetResult(object result)
        {
            this.result = result;
            this.ready.Set();
        }

    }

    class MyQueue
    {
        private static Queue<Request> queue;
        private static AutoResetEvent notEmpty;

        static MyQueue()
        {
            MyQueue.queue = new Queue<Request>();
            MyQueue.notEmpty = new AutoResetEvent(false);
        }

        public static void Send(Request request)
        {
            lock (MyQueue.queue)
            {
                MyQueue.queue.Enqueue(request);
            }
            MyQueue.notEmpty.Set();
        }

        public static Request Receive()
        {
            for (; ; )
            {
                Request result = null;
                lock (MyQueue.queue)
                {
                    if (MyQueue.queue.Count > 0)
                    {
                        result = MyQueue.queue.Dequeue();
                    }
                }
                if (result != null)
                {
                    return result;
                }
                else
                {
                    MyQueue.notEmpty.WaitOne();
                }
            }
        }
    }

    class Program
    {
        static Random random;

        public static void RandomSleep()
        {
            int sleepTime = 0;
            lock (Program.random)
            {
                sleepTime = random.Next(5000);
            }
            Thread.Sleep(sleepTime);
        }

        static void WorkMain(object parameter)
        {
            int threadNumber = Convert.ToInt32(parameter);
            Console.WriteLine("Рабочий поток {0} начал работу.", threadNumber);
            try
            {
                for (; ; )
                {
                    Console.WriteLine("Рабочий поток {0} работает.", threadNumber);
                    Program.RandomSleep();
                    object source = new object();
                    Console.WriteLine("Рабочий поток {0} посылает данные на обработку и ждёт результата.", threadNumber);
                    object result = Request.Call(source);
                    Console.WriteLine("Рабочий поток {0} получил результат обработки данных.", threadNumber);
                }
            }
            catch
            {
                Console.WriteLine("Рабочий поток {0} прервал работу.", threadNumber);
            }
            Console.WriteLine("Рабочий поток {0} закончил работу.", threadNumber);
        }

        static void DialogMain()
        {
            Console.WriteLine("Поток окна начал работу.");
            try
            {
                for (; ; )
                {
                    Console.WriteLine("Поток окна ожидает запроса.");
                    Request request = MyQueue.Receive();
                    Console.WriteLine("Поток окна получил запрос и обрабатывает его.");
                    Program.RandomSleep();
                    Console.WriteLine("Поток окна записывает результат обработки запроса.");
                    request.SetResult(new object());
                }
            }
            catch
            {
                Console.WriteLine("Поток окна прервал работу.");
            }
            Console.WriteLine("Поток окна закончил работу.");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Главный поток начал работу. Запуск дочерних потоков.");
            Program.random = new Random();
            Thread thread;
            for (int i = 1; i <= 2; ++i)
            {
                thread = new Thread(new ParameterizedThreadStart(WorkMain));
                thread.IsBackground = true;
                thread.Start(i);
            }
            thread = new Thread(new ThreadStart(DialogMain));
            thread.IsBackground = true;
            thread.Start();
            Console.WriteLine("Главный поток ждёт нажатия любой клавиши для завершения работы.");
            Console.ReadKey();
            Console.WriteLine("Главный поток завершил работу.");
        }
    }
}
Пример консольный, иллюстрирующий архитектуру решения. Окна, реальные данные - это всё сам приделывай.

Спасибо большое за пример, вечерком постараюсь вникнуть в него)))

Добавлено через 10 часов, 6 минут и 47 секунд:
Код: (C#)
using System;
using System.Collections.Generic;
using System.Threading;

namespace Test
{
    class Request
    {
        public static object Call(object source)
        {
            Request request = new Request();
            request.ready = new AutoResetEvent(false);
            request.source = source;
            request.result = null;
            MyQueue.Send(request);
            request.ready.WaitOne();
            return request.result;
        }

        private object source;
        private object result;
        private AutoResetEvent ready;

        public object GetSource()
        {
            return this.source;
        }

        public void SetResult(object result)
        {
            this.result = result;
            this.ready.Set();
        }

    }

    class MyQueue
    {
        private static Queue<Request> queue;
        private static AutoResetEvent notEmpty;

        static MyQueue()
        {
            MyQueue.queue = new Queue<Request>();
            MyQueue.notEmpty = new AutoResetEvent(false);
        }

        public static void Send(Request request)
        {
            lock (MyQueue.queue)
            {
                MyQueue.queue.Enqueue(request);
            }
            MyQueue.notEmpty.Set();
        }

        public static Request Receive()
        {
            for (; ; )
            {
                Request result = null;
                lock (MyQueue.queue)
                {
                    if (MyQueue.queue.Count > 0)
                    {
                        result = MyQueue.queue.Dequeue();
                    }
                }
                if (result != null)
                {
                    return result;
                }
                else
                {
                    MyQueue.notEmpty.WaitOne();
                }
            }
        }
    }

    class Program
    {
        static Random random;

        public static void RandomSleep()
        {
            int sleepTime = 0;
            lock (Program.random)
            {
                sleepTime = random.Next(5000);
            }
            Thread.Sleep(sleepTime);
        }

        static void WorkMain(object parameter)
        {
            int threadNumber = Convert.ToInt32(parameter);
            Console.WriteLine("Рабочий поток {0} начал работу.", threadNumber);
            try
            {
                for (; ; )
                {
                    Console.WriteLine("Рабочий поток {0} работает.", threadNumber);
                    Program.RandomSleep();
                    object source = new object();
                    Console.WriteLine("Рабочий поток {0} посылает данные на обработку и ждёт результата.", threadNumber);
                    object result = Request.Call(source);
                    Console.WriteLine("Рабочий поток {0} получил результат обработки данных.", threadNumber);
                }
            }
            catch
            {
                Console.WriteLine("Рабочий поток {0} прервал работу.", threadNumber);
            }
            Console.WriteLine("Рабочий поток {0} закончил работу.", threadNumber);
        }

        static void DialogMain()
        {
            Console.WriteLine("Поток окна начал работу.");
            try
            {
                for (; ; )
                {
                    Console.WriteLine("Поток окна ожидает запроса.");
                    Request request = MyQueue.Receive();
                    Console.WriteLine("Поток окна получил запрос и обрабатывает его.");
                    Program.RandomSleep();
                    Console.WriteLine("Поток окна записывает результат обработки запроса.");
                    request.SetResult(new object());
                }
            }
            catch
            {
                Console.WriteLine("Поток окна прервал работу.");
            }
            Console.WriteLine("Поток окна закончил работу.");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Главный поток начал работу. Запуск дочерних потоков.");
            Program.random = new Random();
            Thread thread;
            for (int i = 1; i <= 2; ++i)
            {
                thread = new Thread(new ParameterizedThreadStart(WorkMain));
                thread.IsBackground = true;
                thread.Start(i);
            }
            thread = new Thread(new ThreadStart(DialogMain));
            thread.IsBackground = true;
            thread.Start();
            Console.WriteLine("Главный поток ждёт нажатия любой клавиши для завершения работы.");
            Console.ReadKey();
            Console.WriteLine("Главный поток завершил работу.");
        }
    }
}
Пример консольный, иллюстрирующий архитектуру решения. Окна, реальные данные - это всё сам приделывай.


Еще маленький вопросик по этой же тематике: Предположим есть не модальное окно а компонент в потоке главной формы, ну например текстбокс, и в определенный момент необходимо ввести в него данные и нажать на кнопку для проведения каких либо операций... вопрос собственно в том, как притормозить на время метод подавший запрос на данную операцию? и продолжить его после ввода?

грубо говоря:
1. выполняется какой-то метод.
2. в методе необходимы какие-то либо данные, которые должен ввести пользователь,
по этому - как прервать метод на время, и продолжить его выполнения после того как пользователь введет данные и даст добро.
3. метод благополучно продолжит выполнятся с места разрыва и до конца...

Как такое сделать? Улыбаюсь
« Последнее редактирование: 19-03-2012 15:28 от MasterMan342 » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 19-03-2012 16:03 » new

Цитата: MasterMan342
вопрос собственно в том, как притормозить на время метод подавший запрос на данную операцию? и продолжить его после ввода?
В приведённом примере это явным образом сделано. Разбирайся дальше.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines