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

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

ru
Offline Offline

« : 18-03-2012 14:05 » 

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

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

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

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

ru
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 » 

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

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

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines