Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 156
Текст из файла (страница 156)
рпыгс г)е1едвсе чоха тьгеапясвгс() Следовательно, метод, указываемый в качестве точки входа в поток, должен иметь возвращаемый тип чо1г) и не принимать никаких аргументов. Вновь созданный новый поток не начнет выполняться до тех пор, пока не будет вызван его метод Ясагс (), определяемый в классе тьгеаг(.
Существуют две формы объявления метода ясагс () . Ниже приведена одна из них. рчЫ1с чоха Явагв() Однажды начавшись, поток будет выполняться до тех пор, пока не произойдет возврат из метода, на который указывает точка входа. Таким образом, после возврата из этого метода поток автоматически прекращается. Если же попытаться вызвать метод Яьагь () для потока, который уже начался, это приведет к генерированию исключения ТЬгеаг)ЯСасекхсерп1оп. В приведенном ниже примере программы создается и начинает выполняться новый поток. // Создать поток исполнения. чвгпо Яуввев; пв1по Яуввев.ТЬгеап1пд) с1ввв Мутпгеаг( ( рпЫ1с 1пл Соппш всгьпч Спгг(Навел рпЫ1с МуТЬгеао(вг ггпу паве) ( Соппв 0; Спгг)неве = папе; ) // Точка входа в поток. рчп11с чо1С Кпп() ( Сопво1е.нг1ве) гпе(лпгниаве + " начат."); г)о ( ТЬгеап'.Я1еер(500)г 790 Часть )!.
Библиотека С№ сопво1е.йгъгетгпе("в потоке " ъ гьгбйаве ь Сапог " ъ соцпг)т Соцпг++т ) нп11е(сопле < 10)т Сопво1е.йггсепвпе(гнгбнаве ъ " завершен."); ) ) с1азв Мн1ГТТЬгеаб ( всас1с чо16 Ма1П() ( Сопво1е.Иг1сеьгпе("Основной поток начат."); // Сначала скрнструировать объект типа Мутьгеаб. мутьгеаб вс = пен Мутьгеат)("Потомок №1")т // далее сконструировать поток из этого объекта. Тпгеаб пентнгб = пен Тьгеаб(вс.ппп); // И наконец, начать выполнение потока.
пенТЛгб.зсагс()т бо ( Сопво1е.йг1се(".")т Тнгеаб.З1еер(100)т ) ии11е (вс.сопле )= 10)т Сопво1е.йг1геъхпе("Основной поток завершен.")т ) ) Рассмотрим приведенную выше программу более подробно. В самом ее начале определяется класс Мут)тгеаб, предназначенный для создания второго потока исполнения.
В методе Пцп () этого класса организуется цикл для подсчета от О до 9. Обратите внимание на вызов статического метода з1еер (), определенного в классе Т)тгеаб. Этот метод обусловливает приостановление того потока, из которого он был вызван, на определенный период времени, указываемый в миллисекундах. Когда приостанавливается один поток, может выполняться другой. В данной программе используется следующая форма метода 31еер (): рцб11с всас1с чогб 01еер(ъпс миллисекунд) где миллисекунд обозначает период времени, на который приостанавливается выполнение потока. Если указанное количество миллисекунд равно нулю, то вызывающий поток приостанавливается лишь для того, чтобы предоставить возможность для выполнения потока, ожидающего своей очереди. В методе Маап () создается новый объект типа Т)тгеаб в приведенной ниже последовательности кода.
// Сначала сконструировать объект типа Мутпгеаб. Мутпгеаб вс = пеи Мутпгеас((" Потомок №1")т // далее сконструировать поток из этого объекта. Тпгеаб пентпгб " пеи Тпгеаб(вс.кпп); // И наконец, начать выполнение потока. пеиТЬгб.зсагс()т Глава 23. Многопоточное программирование 791 Как следует из комментариев к приведенному выше фрагменту кода, сначала создается объект типа муТ)тгеаг(.
Затем этот объект используется для создания объекта типа Т)тгеас), для чего конструктору этого объекта в качестве точки входа передается метод шс.Пап(). И наконец, выполнение потока начинается с вызова метода Всагс(). Благодаря этому метод шс. Впп () выполняется в своем собственном потоке. После вызова метода Ясаке () выполнение основного потока возвращается к методу ма№п (), где начинается цикл с(о-нп11е.
Оба потока продолжают выполняться, совместно используя ЦП вплоть до окончания цикла. Ниже приведен результат выполнения данной программы. (Он может отличаться в зависимости от среды выполнения, операционной системы и степени загрузки задач.) Зачастую в многопоточной программе требуется, чтобы основной поток был последним потоком, завершающим ее выполнение. Формально программа продолжает выполняться до тех пор, пока не завершатся все ее приоритетные потоки. Поэтому требовать, чтобы основной поток завершал выполнение программы, совсем не обязательно. Тем не менее этого правила принято придерживаться в многопоточном программировании, поскольку оно явно определяет конечную точку программы. В рассмотренной выше программе предпринята попытка сделать основной поток завершающим ее выполнение.
Для этой цели значение переменной сопле проверяется в цикле с(о-нп11е в методе иа1п (), и как только это значение оказывается равным 10, цикл завершается и происходит поочередный возврат из методов 51еер () . Но такой подход далек от совершенства, поэтому далее в этой главе будут представлены более совершенные способы организации ожидания одного потока до завершения другого. Простые способы усовершенствования многопоточной программы Рассмотренная выше программа вполне работоспособна, но ее можно сделать более эффективной, внеся ряд простых усовершенствований.
Во-первых, можно сделать так, чтобы выполнение потока начиналось сразу же после его создания. Для этого достаточно получить экземпляр объекта типа т)тгеас( в конструкторе класса мут)тгеаг). И во-вторых, в классе Мут)тгеаг( совсем не обязательно хранить имя потока, поскольку для этой цели в классе Т)тгеас) специально определено свойство Паше: рпь11с всг1пд наше ( чесч вест Свойство Паше доступно для записи и чтения и поэтому может служить как для запоминания, так и для считывания имени потока. Основной поток начат.
Потомок №1 начат. ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, ....В потоке Потомок №1, Потомок №1 завершен. Основной поток завершен. сопев соппс Сонет Соппс Сонно Соппс Сопле сопев соппс Соппс = О = 1 = 2 = 3 = 4 = 5 = б = 7 = 8 = 9 792 Часть П, Библиотека Сз Ниже приведена версия предыдущей программы, в которую внесены упомянутые выше усовершенствования. // Другой способ запуска потока.
пзгпч Яузгешт пз1пу Яузсеш.тьгеабгпдт с1азз Мут)тгеаб ( рпь11с гпк Соппкт рпь11с Т)сгеаб Т)тгбт риь11с Мут)сгеаб(зсггпд паве) ( Соппг = от т)тгб пеи тигеаб(кнхз.кпп)т т)сгб.наше = пашет // задать имя потока Тпгб.зкагс()т // начать поток ) // Точка входа в поток. чогс) Рпп() ( Сопзо1е.иггсевапе(ТЬгб.наше + " начат."); с(о ( Тьгеаб.51еер(500)т Сопзо1е.нг1севвпе("В потоке " ь Тйгб.паше + ", Соопк " + Соопс)т Соопк++к ) ин 11е (Соопс < 10) т сопзо1е.иг1геп1пе(тлгб.наше + " завершен.")т ) с1азя Мп1Г1Т)сгеас(1шргочеб ( зкасгс чо1б Маго() ( Сопзо1е. Иг1кет Тпе (" Основной поток начат. ") // Сначала сконструировать объект типа Мут)тгеас).
Мутьгеаб шк = пеи Мут)сгеаб("Потомок Ф1")т бо ( Сопзо1е.Иг).ке(".")т Тнгеаб.Я1еер(100)т ) ни11е (шГ.Сопок ) 10)т Сопзо1е.иг1сеь1пе("Основной поток завершен.")т ) ) Эта версия программы дает такой же результат, как и предыдущая. Обратите внимание на то, что объект потока сохраняется в переменной Тйгб в классе Мут)тгеас). Создание нескольких потоков В предыдущих примерах программ был создан лишь один порожденный поток.
Но в программе можно породить столько потоков, сколько потребуется. Например, в следующей программе создаются три порожденных потока: Глава 23. Многопоточное программирование 793 // Создать несколько потоков исполнения. пя1по Яуясевп пвтпд Яуясеш.ТЬгеаб1пдг с1аяя Мутпгеаб ( рчв11с 1пс Соппс) рпЬ11с ТЬгеаб ТЬгбг рпЬ11с МуТЬгеаб(ясг1пд паве) ( Сопле = 0; ТЬгб = пею ТЬгеаб(гЬ1я.вчп)Г ТЬгб.паше = паше; тпгб.зсагс()г // Точка входа в поток. чогс( апп() ( сопяо1е.иг1геь1пе(тьгб.наше + " начат."); с(о ( Тпгеаб.51еер(500)Г Сопяо1е.иг1сеЬТпе("и потоке " + Тпгб.наше ч Соппс = " + Соипс)Г Соппс++с ) нп11е(Сопла < 10)г Сопво1е.иг1се)апе(ТЬгб.паше + " завершен.")г ) ) с1аяя МогеТЬгеабя ( ясасгс чо1б Маап() ( Сопяо1е.игасевапе("Основной поток начат."); // Сконструировать три потока.