Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Многопоточность.doc
Скачиваний:
4
Добавлен:
28.10.2018
Размер:
225.79 Кб
Скачать

Приоритет потоков

Класс Thread имеет экземплярное свойство Priority, задающее приоритет потока. Его значением является член перечисления ThreadPriority. Названия членов этого перечисления говорят сами за себя. Значение Normal устанавливается по умолчанию. Вы можете сделать приоритет потока больше или меньше. Но что же такое этот приоритет? Может показаться, что потоки с большим приоритетом просто чаще получают кванты времени для своего выполнения. Но на самом деле это не так. На самом деле операционная система всегда выбирает из списка активных потоков поток с наибольшим приоритетом. Поэтому пока в списке активных потоков есть потоки, приоритет которых выше других, будут выполняться только они. Передать выполнение потокам с более низким приоритетом можно, вызвав метод Sleep в потоках с высоким приоритетом. Как уже говорилось, в этом случае данные потоки будут перемещены из списка активных потоков в список спящих потоков и не будут участвовать в распределении квантов времени.

Фоновые потоки и потоки «переднего плана»

У класса Thread есть еще одно свойство, о котором я хотел бы рассказать. Это свойство IsBackground. По умолчанию оно имеет значение false. Данное свойство определяет, является ли поток фоновым (background) или потоком «переднего плана». Как уже сказано, по умолчанию поток является потоком «переднего плана». Что же это такое? В системе Windows существует понятие процесса. Процесс обладает своей изолированой от других процессов памятью. Таким образом разделение на процессы повышает стабильность работы системы, поскольку один процесс не может изменять память другого процесса. Каждый процесс при старте обладает одним потоком. Этот поток называется основным. Однако этот основной поток может порождать другие потоки. Рассмотрим, что произойдет, если основной поток уже завершил свою работу, но есть выполняющийся вторичный поток. Если вторичный поток является потоком «переднего плана», то процесс не будет завершен до тех пор, пока не завершит работу этот вторичный поток. Если же вторичный поток является фоновым, то его работа будет остановлена, и процесс будет завершен. Таким образом фоновые потоки могут не завершить свою работу при закрытии приложения. Поэтому нельзя выносить в фоновые потоки обработку критических данных.

Пришло время подвести итоги по использованию класса Thread. Он имеет следующие достоинства и недостатки:

  1. Легко создавать отдельные потоки.

  2. Существуют легкие в использовании механизмы, позволяющие управлять выполнением потока: приостанавливать его, запускать снова, прерывать поток.

  3. Легко проводить тонкую настройку потока: задавать приоритет, определять, является ли поток фоновым.

  4. Немного затруднен механизм передачи параметров в метод потока.

  5. Имеются только синхронные способы дождаться завершения потока.

Класс ThreadPool

Как уже говорилось ранее, если вы создадите слишком много потоков, то операционная система будет тратить слишком много времени на переключение между ними. С другой стороны так же уменьшится число квантов времени, выделяемых данному конкретному потоку за определенный интервал времени (например, за минуту). Все это может привести к резкому падению производительности не только приложения, которое использует множество потоков, но и всех других приложений на этом компьютере. Для частичного решения этой проблемы .NET предлагает класс ThreadPool (программа ThreadingThreadPool).

Класс ThreadPool имеет ряд возможностей. Он может производить ожидание каких-либо событий от вашего лица, но здесь мы рассмотрим только создание нового потока. Это делается очень просто:

ThreadPool.QueueUserWorkItem(new WaitCallback(CheckPrimeNumber), 1000000021);

Методу QueueUserWorkItem передается делегат WaitCallback описывающий не возвращающий значений метод с одним параметром типа object. Второй параметр метода QueueUserWorkItem – именно то, что будет передано методу делегата WaitCallback. Мы уже рассматривали использование этого параметра для передачи различных данных в метод, выполняемый в отдельном потоке. Все те же методики действенны и здесь.

За счет чего же класс ThreadPool обеспечивает нам выигрыш в производительности? Этот класс создает сразу же несколько потоков (по умолчанию 25 на каждый процессор компьютера). Но это пока неактивные потоки, они не выполняют никакой код, под них просто выделены ресурсы. Когда вы вызываете метод QueueUserWorkItem, ThreadPool выбирает очередной неактивный поток и выполняет в нем ваш метод. По завершению работы вашего метода поток возвращается в пул неактивных потоков. Таким образом происходит переиспользование потоков. Их не приходится создавать и уничножать каждый раз. Если же вы поставили в очередь слишком много методов на выполнение в отдельных потоках, и в пуле не осталось свободных неактивных потоков, то ThreadPool создаст новые потоки для вас. Но новый поток создается не чаще, чем раз в пол секунды. Это гарантирует, что не будет предпринята попытка создать сразу много потоков. Кроме того, за очередные пол секунды какой-либо из выполняемых методов может закончить свою работу и освободить поток. Тогда создание нового потока не потребуется. В общем, Microsoft рекомендует использовать ThreadPool вместо Thread когда это только возможно. Большинство технологий Microsoft, созданных в рамках .NET, используют именно его.

Подведем итоги. Класс ThreadPool имеет следующие достоинства и недостатки:

  1. Наверно простейший способ создать отдельный поток.

  2. Оптимизирован для работы со множеством потоков.

  3. Практически никаких механизмов управления или ожидания завершения работы.