Г. Шилдт - С#4.0 Полное руководство (1160795), страница 167
Текст из файла (страница 167)
Намного более важной оказывается поддержка в СФ многопоточной обработки, благодаря которой упрощается написание высокопроизводительных, многопоточных программ на СФ по сравнению с некоторыми другими языками программирования. Классы, поддерживающие многопоточное программирование, определены в пространстве имен эуагев.
ТпгеагтТпд. Поэтому любая многопоточная программа на СФ включает в себя следующую строку кода. иегпп Буегев.тьгеаегпщ Класс тЬгеас1 Система многопоточной обработки основывается на классе Тпгеаб, который инкапсулирует поток исполнения. Класс тттгеаст является гермепгичным, т.е. он не может наследоваться. В классе Тттгеаб определен ряд методов и свойств, предназначенных для управления потоками.
На протяжении всей этой главы будут рассмотрены наиболее часто используемые члены данного класса. 83б Часть П. Библиотека С(г Создание и запуск потока Для создания потока достаточно получить экземпляр объекта типа Т)ггеас(, т.е. класса, определенного в пространстве имен Яуясет. Т)ггеаг)1пд. Ниже приведена простейшая форма конструктора класса Т(тгеас(: ро)с11с Тпгеаг( (Т)1геаг(зсагс запуск) где запуск — это имя метода, вызываемого с целью начать выполнение потока, а Т)ггеас(ЯСагс — делегат, определенный в среде .(ЧЕТ Ргатегчог)с, как показано ниже.
ро)с11с г)е1есасе чо1б Тйгеаг)зсагс() Следовательно, метод указываемый в качестве точки входа в поток, должен иметь возвращаемый тип чогс( и не принимать никаких аргументов. Вновь созданный новый поток не начнет выполняться до тех пор, пока не будет вызван его метод Ягагг (), определяемый в классе Т)ггеас(. Существуют две формы объявления метода Ясагс () . Ниже приведена одна из них. рпьттс чогг( ясагс() Однажды начавшись, поток будет выполняться до тех пор, пока не произойдет возврат из метода, на который указывает запуск. Таким образом, после возврата из этого метода поток автоматически прекращается. Если же попытаться вызвать метод Ясагс () для потока, который уже начался, это приведет к генерированию исключения Т)ггеас(ЯсасеЕхсерс1оп.
В приведенном ниже примере программы создается и начинает выполняться новый поток. О Создать поток исполнения. пягпс Яуясеш; оя1пд Буясеш.ТЛгеаоьпсг с1аяв МуТьгеаа ( ро)з11с 1пс Сопок; ясггпч г)ггг)наше) ро)с11с Мутпгеаг((астапов паве) ( Соопс = 0; г)гганаше = паве; ) О Точка входа в поток. ро511с чо1с( Кпп() ( Сопяо1е.нгзсеъьпе(сагднаше т " начат."); г(о ( Т)ягеаг(.51еер(500); сопяо1е.игггеььпе("в потоке " е гпгонаше е ", соопг = " е соопг)г Соппгае; ни11е(соопс < 10); Сопяо1е.игггесгпе(гпгс(наше е " завершен."); ) Глава 23.
Многопаточное программирование. Часть первая: основы 837 с1авв Мц1аъТЬгеаб ( вьаг1с чоьб Маьп() ( Сопво1е.ив1пеъьпе("Основной поток начат."); !/ Сначала сконструировать объект типа МуТЬгеаб. МуТЬгеаб шь = пен МуТЬгеаб("Потомок ()1"); !/ Палее сконструировать поток из этого объекта. ТЬгеаб пенТЬгб = пеи ТЬгеаб(шп.йцп)г УУ И наконец, начать выполнение потока.
пентьгб.зоагг()Г бо ( Сопво1е.иг1пе(".")г ТЬгеаб.э1еер(100)г ньь1е (шг.сонно != 10); Сопво1е.Хгьгеъьпе("Основной поток завершен.") ) Рассмотрим приведенную выше программу более подробно. В самом ее начале определяется класс МуТЬгеаб, предназначенный для создания второго потока исполнения.
В методе рцп () этого класса организуется цикл для подсчета от 0 до 9. Обратите внимание на вызов статического метода 01еер (), определенного в классе ТЬгеаб. Этот метод обусловливает приостановление того потока, из которого он был вызван, на определенный период времени, указываемый в миллисекундах. Когда приостанавливается один поток, может выполняться другой.
В данной программе используется следующая форма метода 01еер (): рцЫ1с всасьс ноьб 51еер(ъпс миплисекунл простоя) где миллисекунд простоя обозначает период времени, на который приостанавливается выполнение потока. Если указанное количество миллисекунд простоя равно нулю, то вызывающий поток приостанавливается лишь для того, чтобы предоставить возможность длл выполнения потока, ожидающего своей очереди. В методе Маьп () новый объект типа ТЬгеаб создается с помощью приведенной ниже последовательности операторов.
Сначала сконструировать объект типа МуТЬгеаб. МуТЬгеаб шс = пеи МуТЬгеаб("Потомок ()1")г О Палее сконструировать поток из этого объекта. ТЬгеаб пеиТЬгб = пен ТЬгеаб(шг.ппп)г У/ И наконец, начать выполнение потока. пентЬгбгябагп()г Как следует из комментариев к приведенному выше фрагменту кода, сначала создается объект типа МуТЬгеаб. Затем этот объект используется для создания объекта типа ТЬгеаб, для чего конструктору этого объекта в качестве точки входа передается метод шс .
Пцп ( ) . И наконец, выполнение потока начинается с вызова метода Б С ах с ( ) . 838 Часть П. Библиотека С№ Благодаря этому метод шС . Впп () выполняется в своем собственном потоке. После вызова метода ЯСагС () выполнение основного потока возвращается к методу Маьп (), где начинается цикл с(о-н)711е. Оба потока продолжают выполняться, совместно используя ЦП, вплоть до окончания цикла. Ниже приведен результат выполнения данной программы. (Он может отличаться в зависимости от среды выполнения, операционной системы и степени загрузки задач.) Зачастую в многопоточной программе требуется, чтобы основной поток был последним потоком, завершающим ее выполнение. Формально программа продолжает выполняться до тех пор, пока не завершатся все ее приоритетные потоки.
Поэтому требовать, чтобы основной поток завершал выполнение программы, совсем не обязательно. Тем не менее этого правила принято придерживаться в многопоточном программировании, поскольку оно явно определяет конечную точку программы. В рассмотренной выше программе предпринята попытка сделать основной поток завершающим ее выполнение. Для этой цели значение переменной Соппг проверяется в цикле г)о-мп11е внутри метода Масп (), и как только это значение оказывается равным 10, цикл завершается и происходит поочередный возврат из методов 51еер () . Но такой подход далек от совершенства, поэтому далее в этой главе будут представлены более совершенные способы организации ожидания одного потока до завершения другого.
Простые способы усовершенствования многопоточной программы Рассмотренная выше программа вполне работоспособна, но ее можно сделать более эффективной, внеся ряд простых усовершенствований. Во-первых, можно сделать так, чтобы выполнение потока начиналось сразу же после его создания. Для этого достаточно получить экземпляр объекта типа Т)ггеао в конструкторе класса МуТЬгеаг1 И во-вторых, в классе мут)згеаг( совсем не обязательно хранить имя потока, поскольку для этой цели в классе Т)7геас( специально определено свойство Мате. ро)с11с агсспо Ваше ( чегг зеС; ) Свойство Маше доступно для записи и чтения и поэтому может служить 'как для запоминания, так и для считывания имени потока. Ниже приведена версия предыдущей программы, в которую внесены упомянутые выше усовершенствования.
Основной поток начат. Потомок №1 начат. ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, Потомок №1 завершен. Основной поток завершен. соппс Соопс Соопс соопс Соппс Соопс соппс соопг. Сочно соппс = О 1 = 2 = 3 4 = 5 — 6 — 7 — в 9 Глава 23.
Многопоточное программирование. Часть первая: основы 839 // Другой способ запуска потока. оягпп Буясеш; ояьпч Буясеш.ТЛгеабьпп; с1аяя Мутлгеаб ( роЫьс ьпд Соопс; роЫТс Тпгеаб Тнгб; роЬ11с Мутнгеаб(ясггпп паве) ( Сопля = 0~ тлгб = пен тдгеаб(гл1я.коп)г тпгб.наше = паве; // задать имя потока Тпгб.всадя(); // начать поток // Точка входа в поток. чоха Кпп() Сопяо1е.иггсет Тле(тлгб.каше + " начат."); бо ( Тпгеаб.51еер(500)г сопяо1е.нгьсеьгпе("в потоке " ъ тпгб.наше + ", соопг = " + соипд)г Соопс++Г ) нЫ1е(Соопс < 10)) сопяо1е.нгьгеььпе (тнгб.наше + " завершен."); ) ) с1аяя Мо1ГТТЬгеаб1шргочеб ( ягаг1с чогб Ма1п() ( Сопяо1е. Нгьсеььпе (" Основной поток начат.
"); Сначала сконструировать объект типа Мутлгеаб. Мутпгеаб шг = пен Мутпгеаб("Потомок $1")г бо ( Сопяо1е.иггсе(".")Г ТЛ аб. Бгеер Ы00); ) ип11е (шГ.Соппд != 10) г Сопяо1е.нг1сеъьпе("Основной поток завершен."); ) Зта версия программы дает такой же результат, как и предыдущая.
Обратите внимание на то, что объект потока сохраняется в переменной Т)тгб из класса Мут)тгеаб. Создание нескольких потоков В предыдущих примерах программ был создан лишь один порожденный поток. Но в программе можно породить столько потоков, сколько потребуется. Например, в следующей программе создаются три порожденных потока. О создать несколько потоков исполнения. 840 Часть )1. Библиотека С№ пятно Яуясев," пя1по яуясев.тьгеаббпсп с1аяв МуТЬгеаб ( РПЫ1С ТПС СОППС1 рпЫТс ТЬгеаб ТЬгб; рпЫтс МуТЬгеаб(ягг1по папе) ( Соппг = 0; ТЬгб = пен ТЬгеаб(СЬгя.рпп); ТЬгб.наве = паве; ТЬгб.ЯСагС(); ) // Точка входа в поток.