Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 165
Текст из файла (страница 165)
Многопоточное программирааанне 831 вс1.тьгт).аьогс(100)т вс1.тпгг).зогп()Г // ожидать прерывания потока Сопзо1е.иг1сеььпе("Основной поток прерван."); ) Эта программа дает следующий результат: Мой Поток начат 1 2 3 4 5 б 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Прерывание потока. Поток прерван, кпд завершения 100 Основной патон прерван. Как следует из приведенного выше результата, значение 100 передается методу йьогг() в качестве кода прерывания.
Это значение становится затем доступным посредством свойства ехсерг1опзгаге из класса исключения тьгеасйЬоггехсерг1оп, которое перехватывается потоком при его прерывании. Отмена действия метода алло~~ () Запрос на преждевременное прерывание может быть переопределен в самом потоке. Для этого необходимо сначала перехватить в потоке исключение тьге асп)ьо го ех с ер г 1оп, а затем вызвать метод не зегйЬогг () . Благодаря этому исключается повторное генерирование исключения по завершении обработчика исключения, прерывающего данный поток. ниже приведена форма объявления метода еезегйьогг () .
рпЬаьс зсасгс тома НезеГЛЬогс () Вызов метода Незег))ЬОТГ () может завершиться неудачно, если в потоке отсутствует надлежащий режим надежной отмены преждевременного прерывания потока. В приведенном ниже примере программы демонстрируется применение метода ЕезеГАЬОгс () . // Испольэовать метод везегАЬогг() пз1пч зузсепи нзьпц зузсев.ТЬгеаогпдт с1азз Мутьгеаг( ( рпЬ11с тьгеао Тпгбп риьтгс Мутьгеаг)(зсг1пд паве) ( тпгг( = пен Тпгеан(гпьз.нпп)т Тпгг(.паве = пашет тпгг(.зсагс()7 ) // Это точка входа з ноток.
832 Часть П. Библиотека Са чоао Рлп() ( Сопяо1е.ИггсеЬТпе (Тпгп.Наше ь " начат.",) т Тог(1пг 1 = 1т 1 <= 1000т 1ь+) ( сгу ( Сопяо1е.нгаге 01 + '" ") ) 16((1%10)==0) ( Сопяо1е.Игагеьапе()! Тпгеао.51еер(250)) ) ) сассь(тьгеадАьогсехсерсаоп ехс) ( 16((апг)ехс.Ехсерггопзгасе == О) ( Сопяо1е.игасе11пе("Прерывание потока отменено! "код завершения " + ехс.Ехсергаоп5саге)т Тпгеас(.иеяеглпогг()т е1яе сопяо1е.иггсеьапе("поток прерван, код завершения " + ехс.Ехсерсгоп5сасе); сопяо1е.иг1сеьгпе(тьгс(.наше я " завершен нормально."); ) с1авя НеяеГАЬогс [ ягагас зови Ма1п() ( Мутпгеак(шс1 = пен Мутпгеак(("Мой Поток")т Тпгеат(.51еер(1000)т // разрешить порожденному потоку // начать свое выполнение Сопяо1е.нггге11пе("Прерывание потока.")т шг1.ТЬгС.АЬогс(0)) // зто не остановит поток Тпгеас.51еер(1000)т // разрешить порожденному потоку // выполняться чуть дольше Сопяо1е.ИгггеЬТпе("Прерывание потока."); шс1.ТЬгО.АЬогс(100)т // а зто остановит поток шс1.ТЬгп.зогп()т // ожидать прерывания потока Сопяо1е.нггсеаапе("Основной поток прерван.")т ) ) Ниже приведен результат выполнения этой программы.
Мой Поток начат 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Прерывание потока. Прерывание потока отменено! Код завершения 0 Глава 23. Миоголоточиое программирование 833 Если в данном примере программы метод ))Ьогг () вызывается с нулевым аргументом, то запрос на преждевременное прерывание отменяется потоком, вызывающим метод йеэеСВЬогС (), и выполнение этого потока продолжается. Любое другое значение аргумента приведет к прерыванию потока.
Приостановка и возобновление потока В первоначальных версиях среды .НЕТ Егашеп ог)с поток можно было приостановить вызовом метода Тпгеац. Бпзрепг) () и возобновить вызовом метода тьгеас). Пеэише () . Но теперь оба этих метода считаются устаревшими и не рекомендуются к применению в новом коде.
Объясняется зто, в частности, тем, что пользоваться методом Бпэрепг( () на самом деле небезопасно, так как с его помощью можно приостановить поток, который в настоящий момент удерживает блокировку, что препятствует ее снятию, а следовательно, приводит к взаимоблокировке. Применение обоих методов может стать причиной серьезных осложнений на уровне системы. Поэтому для приостановки и возобновления потока следует использовать другие средства синхронизации, в том числе мьютекс и семафор. Определение состояния потока Состояние потока может быть получено из свойства тьгеас)БСаге, доступного в классе ТЬгеагь Ниже приведена общая форма этого свойства. риь11с тьгеаг)зсасе тьгеаг)зсасе( Песа ) Состояние потока возвращается в виде значения, определенного в перечислении тьгеас(Бсасе.
Ниже приведены значения, определенные в этом перечислении. Тпгеаг)згаСе.льогСео Тпгеаг)згаге.вассчгоппг) Тпгеаг)згаге.згорреп Тьгеапзгаге.зпэрепоег) Тьгеапзгаге.ппэгаггеп Все эти значения не требуют особых пояснений, за исключением одного. Значение тьгеас(Бсасе. на1с81еер301п обозначает состояние, в которое поток переходит во время ожидания в связи с вызовом метода Иааг (), 51еер () или го1п () . Применение основного потока Как пояснялось в самом начале этой главы, у всякой программы на С№ имеется хотя бы один поток исполнения, называемый основным.
Этот поток программа получает автоматически, как только она начинает выполняться. С основным потоком можно обращаться таким же образом, как и со всеми остальными потоками. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 Поток прерван, кол завершения 100 Основной поток прерван. Тпгеаг)згаге.кпоггвеппеагег) тпгеаг)зсасе.кппп1пч Тпгеаозгаге.БСорнейпеагео ТпгеаОБСаСе.зпареппаейиеэгеп тьгеаозсасе.иасс81еерюо1п 834 Часть П. Библиотека С() Для доступа к основному потоку необходимо получить объект типа т)тгеак(, который ссылается на него.
Это делается с помощью свойства Сиггепстйгеаб, являющегося членом класса Тйгеаб. Ниже приведена общая форма этого свойства. риььгс вгаггс тьгеаб сиггепгтьгеаб( дег) ) Данное свойство возвращает ссылку на тот поток, в котором оно используется.
Поэтому если свойство Сиггепот)тгеак( используется при выполнении кода в основном потоке, то с его помощью можно получить ссылку на основной поток. Имея в своем распоряжении такую ссылку, можно управлять основным потоком так же, как и любым другим потоком. В приведенном ниже примере программы сначала получается ссылка на основной поток, а затем получаются и устанавливаются имя и приоритет основного потока. // Продемонстрировать управление основным потоком. ив1пд зувгевт ияьпо 5увсев.тпгеад1пст с1авв Овемагп ( всасьс тотб Магп() ( Тьгеаб Того( // Получить основной поток. Тпгб = Тьгеаб.сиггепстпгеабт // Отобразить имя основного потока.
1Г(тьгб.Мазе == пи11) Сопво1е.нг1сеь1пе("У основного потока нет имени."); е1ве сопво1е.игггеьгпе("Основной поток называется: " + тпгб.мазе)т // Отобразить приоритет основного потока. сопво1е.иг1геь1пе("приоритетк " + тпгб.рггогггу)т Сопво1е.нггсеьгпе()т // Установить имя и приоритет. Сопво1е.нг1севьпе("Установка имени и приоритета. 1п") Тпгк(.нане = "Основной Поток"; тпгб.рг1ог1гу = тпгеабрг1ог1гу.льотемогва1( Сопво1е.иг1севьпе("Теперь основной поток " + "называется: " + Тьгб.Маме)т Сопво1е.иг1ге11пе("Теперь приоритет: " + Тьгб.рггог1ГУ)т ) ) Ниже приведен результат выполнения этой программы. У основного потока нет имени.
Приоритет: Могва1 Глава 23. Многопоточное программирование 835 Установка имени и приоритета. Теперь основной поток называется: Основной Поток Теперь приоритет: АЬотеногеа1 Следует, однако, быть очень внимательным, выполняя операции с основным потоком. Так, если добавить в конце метода Ма1п () следующий вызов метода По1п (): тьгс(.
Погп () и программа никогда ие завершится, поскольку оиа будет ожидать окончания осиовиого потока! Рекомендации по многопоточному программированию Самое главное для зффективиого многопоточного программирования — мыслить категориями параллельного, а ие последовательного выполнения кода. Так, если в одной программе имеются две подсистемы, которые могут работать параллельно, их следует организовать в отдельные потоки. Но делать это следует очень внимательно и аккуратно, поскольку если создать слишком много потоков, то тем самым можно значительно снизить, а ие повысить производительность программы.
Следует также иметь в виду дополнительные издержки, связанные с переключением контекста. Так, если создать слишком много потоков, то иа смену контекста уйдет больше времени ЦП, чем иа выполнение самой программы! Запуск отдельной задачи Многозадачность иа основе потоков чаще всего организуется при программировании иа С№. Но там, где зто уместно, можно организовать и многозадачность иа основе процессов. В этом случае вместо запуска другого потока в одной и той же программе одна программа начинает выполнение другой.
При программировании иа С№ зто делается с помощью класса Ргосезз, определенного в пространстве имен Зузгем. П1аппозг1сз. В заключение этой главы вкратце будут рассмотрены особенности запуска и управления другим процессом. Простейший способ запустить другой процесс — воспользоваться методом зсагс Н, определенным в классе Ргосезз. Ниже приведена одна из самых простых форм этого метода. рпььгс вгаггс ргосевв згагг(вгггпо имя) где имя обозначает конкретное имя файла, который должен исполняться или же связан с исполняемым файлом.