Информация об изменениях

Сообщение Красивое решение для задачи с потоками от 12.03.2015 21:06

Изменено 12.03.2015 21:08 Cynic

Требуется найти "красивое" решение для следующей задачи.
Есть четыре потока: один "управляющий", и три "вычислительных". Задача "управляющего потока" раздавать задачи "вычислительным потокам", а задача "вычислительных" выполнять эти задачи. При этом "вычислительные потоки" должны работать по следующему алгоритму:
  • Стоит на паузе в ожидании задачи
  • Получает очередную задачу
  • Получает команду на старт
  • Выполняет вычисления
  • Становится на паузу в ожидании следующей задачи (возврат к первому пункту списка)
Кроме того:
  • Все три потока должны начинать работу "одновременно" (это ограничение само появляется из следующего требования)
  • Каждый поток должен дожидаться пока остальные два потока не выполнят работу
  • Управляющий поток должен дожидаться пока все вычислительные потоки не встанут на паузу и только после этого раздавать им задачи
  • Каждый поток должен быть создан только один раз
Пытаясь решить эту задачу я написал следующий тестовый пример:
    class Program
    {
        static AutoResetEvent mt = new AutoResetEvent(false);
        static AutoResetEvent th1 = new AutoResetEvent(false);
        static AutoResetEvent th2 = new AutoResetEvent(false);
        static AutoResetEvent th3 = new AutoResetEvent(false);

        static Thread mainThread;
        static Thread thread1;
        static Thread thread2;
        static Thread thread3;

        static void Main(string[] args)
        {
            mainThread = new Thread(MainThread);
            mainThread.IsBackground = true;

            thread1 = new Thread(Thread1);
            thread1.IsBackground = true;

            thread2 = new Thread(Thread2);
            thread2.IsBackground = true;

            thread3 = new Thread(Thread3);
            thread3.IsBackground = true;

            thread1.Start();
            thread2.Start();
            thread3.Start();
            mainThread.Start();

            Console.ReadLine();
        }

        static void MainThread()
        {
            while (true)
            {
                Console.Write("\nT ");

                if ((thread1.ThreadState & ThreadState.WaitSleepJoin) != ThreadState.WaitSleepJoin ||
                    (thread2.ThreadState & ThreadState.WaitSleepJoin) != ThreadState.WaitSleepJoin ||
                    (thread3.ThreadState & ThreadState.WaitSleepJoin) != ThreadState.WaitSleepJoin)
                {
                    mt.WaitOne();
                }

                if ((thread1.ThreadState & ThreadState.Running) == ThreadState.Running ||
                    (thread2.ThreadState & ThreadState.Running) == ThreadState.Running ||
                    (thread3.ThreadState & ThreadState.Running) == ThreadState.Running)
                {
                    th1.Set();
                    th2.Set();
                    th3.Set();
                }

                Thread.Sleep(1000);
            }
        }

        static void Thread1()
        {
            while (true)
            {
                mt.Set();
                th1.WaitOne();
                Console.Write("1");
            }
        }

        static void Thread2()
        {
            while (true)
            {
                mt.Set();
                th2.WaitOne();
                Console.Write("2");
            }
        }

        static void Thread3()
        {
            while (true)
            {
                mt.Set();
                th3.WaitOne();
                Console.Write("3");
            }
        }
    }

И всё вроде работает, но есть две вещи которые меня не устраивают:
  • Наличие большого количества экземпляров AutoResetEvent
  • Необходимость выполнять проверку состояния потока через ThreadState
Не устраивают они меня потому, что пока нужно только три "вычислительных" потока с этим можно жить, а представьте во что это превратить если их будет пару десятков.
Поэтому решил спросить Вас, есть ли способ более красиво решить требуемую задачу?
Требуется найти "красивое" решение для следующей задачи.
Есть четыре потока: один "управляющий", и три "вычислительных". Задача "управляющего потока" раздавать задачи "вычислительным потокам", а задача "вычислительных" выполнять эти задачи. При этом "вычислительные потоки" должны работать по следующему алгоритму:
  • Стоит на паузе в ожидании задачи
  • Получает очередную задачу
  • Получает команду на старт
  • Выполняет вычисления
  • Становится на паузу в ожидании следующей задачи (возврат к первому пункту списка)
Кроме того:
  • Все три потока должны начинать работу "одновременно" (это ограничение само появляется из следующего требования)
  • Каждый поток должен дожидаться пока остальные два потока не выполнят работу
  • Управляющий поток должен дожидаться пока все вычислительные потоки не встанут на паузу и только после этого раздавать им задачи
  • Каждый поток должен быть создан только один раз
Пытаясь решить эту задачу я написал следующий тестовый пример:
    class Program
    {
        static AutoResetEvent mt = new AutoResetEvent(false);
        static AutoResetEvent th1 = new AutoResetEvent(false);
        static AutoResetEvent th2 = new AutoResetEvent(false);
        static AutoResetEvent th3 = new AutoResetEvent(false);

        static Thread mainThread;
        static Thread thread1;
        static Thread thread2;
        static Thread thread3;

        static void Main(string[] args)
        {
            mainThread = new Thread(MainThread);
            mainThread.IsBackground = true;

            thread1 = new Thread(Thread1);
            thread1.IsBackground = true;

            thread2 = new Thread(Thread2);
            thread2.IsBackground = true;

            thread3 = new Thread(Thread3);
            thread3.IsBackground = true;

            thread1.Start();
            thread2.Start();
            thread3.Start();
            mainThread.Start();

            Console.ReadLine();
        }

        static void MainThread()
        {
            while (true)
            {
                Console.Write("\nT ");

                if ((thread1.ThreadState & ThreadState.WaitSleepJoin) != ThreadState.WaitSleepJoin ||
                    (thread2.ThreadState & ThreadState.WaitSleepJoin) != ThreadState.WaitSleepJoin ||
                    (thread3.ThreadState & ThreadState.WaitSleepJoin) != ThreadState.WaitSleepJoin)
                {
                    mt.WaitOne();
                }

                if ((thread1.ThreadState & ThreadState.Running) == ThreadState.Running ||
                    (thread2.ThreadState & ThreadState.Running) == ThreadState.Running ||
                    (thread3.ThreadState & ThreadState.Running) == ThreadState.Running)
                {
                    th1.Set();
                    th2.Set();
                    th3.Set();
                }

                Thread.Sleep(1000);
            }
        }

        static void Thread1()
        {
            while (true)
            {
                mt.Set();
                th1.WaitOne();
                Console.Write("1");
            }
        }

        static void Thread2()
        {
            while (true)
            {
                mt.Set();
                th2.WaitOne();
                Console.Write("2");
            }
        }

        static void Thread3()
        {
            while (true)
            {
                mt.Set();
                th3.WaitOne();
                Console.Write("3");
            }
        }
    }

И всё вроде работает, но есть две вещи которые меня не устраивают:
  • Наличие большого количества экземпляров AutoResetEvent
  • Необходимость выполнять проверку состояния потока через ThreadState
Не устраивают они меня потому, что пока нужно только три "вычислительных" потока с этим можно жить, а представьте во что это превратитьcz если их будет пару десятков.
Поэтому решил спросить Вас, есть ли способ более красиво решить требуемую задачу?