Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 96
Текст из файла (страница 96)
Если поток вызвал "родную" функцию через уровень Р/1пто(се, и эта функция требует длительного времени на выполнение, то прерывание потока откладывается до тех пор, пока управление не вернется в управляемое пространство. На заметку! В .МЕТ 2.0 и последующих версиях при выполнении блока 11па11у доставка тьгеас(Аьогсехсерс1оп откладывается до тех пор, пока выполнение не покинет блок 11па11у. В .МЕТ ).х исключение прерывания доставляется в любом случае. Вызов АЬогг на потоке не прерывает его принудительно, поэтому если нужно ждать до тех пор, пока поток действительно не завершит выполнение, понадобится вызвать ,того на этом потоке, чтобы подождать до тех пор, пока не завершится код обработчика исключения ТпгеасйЬогСЕхсергаоп. Во время этого ожидания имеет смысл установить таймаут, чтобы не ждать вечно, пока поток завершит уборку за собой.
Несмотря на то что код в обработчике исключений должен подчиняться другим правилам кодирования обработчиков, существует вероятность, что обработчику понадобится немало времени, а то и бесконечно много, чтобы завершить работу. Давайте посмотрим, как функционирует обработчик ТЬгеас1АЬогСЕхсерс1оп; пя1пд Яуясеш; пя1пд Яуягеш.Тпгеапгпдт рпЬ1гс с1аяя ЕпггуРогпс рггчяге згаггс то10 Тпгеаорппс() ( п1опд соппсег = От нб11е( Сгпе ) ( сгу сопяо1е.иг1се11пе( "(О)", соппсег+ь )т ) сассп( Тпгеас(АЬогскхсерг1оп ) ( /! Попытка проглотить исключение и продолжиться.
Сопяо1е.нг1ге11пе( "Прекратить(" )т ягаггс нога Ма1п() ( Тпгеас)пентпгеас( = пен Тнгеас)( пен Тпгеаозгагс(впсгуро1пг.тлгеас)гппс) ) пентьгеас(.ягагс()г ТЬгеас(.Я1еер( 2000 ); !/ Прервать поток. пентпгеас(.АЬогг()1 /! Ждать завершения потока. пентпгеас(.эо1п()т Зямб Глава ! 2 После беглого взгляда на код может показаться, что вызов боап на экземпляре пен1пзгапсе заблокирует выполнение навсегда. Однако этого не случается. Казалось бы, поскольку тпгеат!АЬоггехсергаоп обрабатывается внутри цикла функции потока, исключение будет проглочено" и цикл продолжится, независимо от того.
сколько раз главный поток попытается прервать данный поток. Однако исключение тпгеат!АЬоггехсергаоп, сгенерированное через метод тпгеас!. АЬогг, ведет себя особым образом. Когда поток завершает обработку исключения, исполняющая среда заново неявно генерирует его в конце обработчика. Это все равно, как если бы вы сами повторно сгенерировали исключение. Таким образом, любые внешние обработчики или блоки Тапа11у будут выполняться нормально. В примере вызов Уогп не будет ждать вечно, как можно было предполагать. Повторную генерацию системой исключения тпгеаоАЬо ггехсерг !.оп можно предотвратить, вызвав статический метод тьгевс!. Аезегльогг. Однако общая рекомендация предусматривает вызов Резегльогг только из потока, вызвавшего Аьогг.
Если нужно, чтобы зто происходило внутри обработчика исключения тьгеас!АЬоггехсерстоп прерываемого потока, понадобится применить сложную технику внутрипотокового взаимодействия. Если вы пришли к заключению о необходимости реализации такой техники отмены прерывания потока, то зто, скорее всего, свидетельствует о том. что вам, прежде всего, стоит пересмотреть дизайн своей системы. Другими словами, вто признак плохого дизайна! Хотя исполняющая среда обеспечивает намного более ясный механизм для прерывающихся потоков, такой как информирование заинтересованных сторон о факте прерывания потока, все равно обработчик тьгеас!Аьоггехсерг1оп должен быть реализован правильно.
На заметку! Тот факт, что экземпляры тпгеаг!АЪоггехсерг1оп могут генерироваться асинхронно в произвольном управляемом потоке, затрудняет создание устойчивого, безопасного к исключениям кода, Прочтите раздел "Ограниченные области выполнения" в главе 7. Останавливающиеся и пробуждающиеся потоки Как и для внутренних потоков операционной системы, существуют механизмы для погружения управляемых потоков в сон на определенный период времени или приостановки выполнения до тех пор, пока оно не будет явно возобновлено.
Если поток просто желает приостановить себя на предопределенный период времени, он может вызвать статический метод тьгеат!. Е1еер и перейти в состояние иаагБ1еердогп. Единственный параметр, передаваемый методу Я1еер — это количество миллисекунд, в течение которых поток должен находиться в спящем состоянии. После вызова этот метод заставляет поток отдать остаток кванта времени.
выделенного ему процессором, и отправиться спать. По истечении указанного времени планировщик потоков возобновит его выполнение. Естественно. промежуток времени, который передается Е1 сер. довольно точен, но не абсолютно. Это связано с тем, что в конце периода поток не получает немедленно времени процессора. В этот момент может выполняться другой.
высокоприоритетный поток. и пробуждающемуся потоку придется подождать своей очереди. По этой причине применение Б1еер для синхронизации выполнения между двумя потоками категорически не рекомендуется. Внимание! Если вы обнаружите, что дпя решения проблемы синхронизации в коде нужно применить Е1еер, знайте — подобным образом проблема не решится вообще. Она будет закамуфлирована и тем самым только усугубится.
Многопоточность в С№ 367 Чтобы усыпить поток навсегда, предусмотрено специальное значение Т1гдеоцс. 1пг1паге, которое можно передать Б1еер. Разбудить спящий поток можно, прервав его методом экземпляра ТпгеасГ. 1псеггцрс. Этот метод подобен АЬогс в том, что он пробуждает целевой поток и генерирует исключение тьгеасг1пгеггцргесгехсерг1оп. Поэтому, если функция потока не оснащена обработчиком этого исключения, оно будет распространяться по стеку до тех пор, пока выполнение потока не прекратится из-за необработанного исключения. Если действительно необходимо реализовать изменяемое состояние сна, используя этот механизм, то для подстраховки потребуется поместить вызов Б1еер внутрь блока г ту и перехватывать исключение тьгеас11пгег гцргехсер гас п.
В отличие от ТЬгеастАЬогГЕхсерс1оп,исключение Тпгеас11псеггцрГЕхсерг1оп автоматически не повторяется исполняющей средой в конце обработчика. Однако обратите внимание, что реализовывать изменяемый механизм сна никогда не придется, потому что тип мопьгог, который описывается ниже, предлагает более эффективный путь достижения той же цели. на заметку! Еще одним специальным значением параметра для тьгеасг. Б1еер является О.
если передается О, то метод ТпгеасГ. Б1еер заставит поток отдать остаток выделенного ему кванта времени. Возобновление выполнения такого потока произойдет тогда, когда планировщик потоков вернется к нему снова. При работе на платформе .НЕТ 4.0 или последующей версии вместо этого следует использовать метод ТлгеасГ. Узе1Ф Другой способ отправить поток в состояние сна на неопределенное время предоставляет метод экземпляра тпгеаст. Япзрепсь Вызов Бцзрепс1 приостанавливает выполнение потока до тех пор, пока оно не будет явно возобновлено. Возобновить выполнение потока можно вызовом метода экземпляра Еезцгяе или 1псеггцрс. Однако в случае применения 1псеггцрг целевой поток должен иметь корректный обработчик исключений вокруг вызова Бцзрепс1, иначе поток моясет быть завершен.
Формально вызов АЬогс также возобновляет выполнение потока, но лишь затем, чтобы отправить ему тьгеасгльоггехсерсгоп н, в конечном счете, заставить завершиться. имейте в виду, что любой поток с достаточными привилегиями может вызвать Бпзрепсг на потоке— даже текущий поток на самом себе. Если текущий поток вызывает Б перепл, в этой точке он блокируется, ожидая следующего вызова Не зцлсе. Важно отметить, что когда на потоке вызывается Бпзрепс1 поток не приостанавливается немедленно. Вместо этого потоку разрешено выполняться до т.н. безопасной пючки.
Достигнув этой точки, поток приостанавливается. Безопасная точна — это место в управляемом коде. где можно провести сборку мусора. Например, если среда СЬК определяет, что пришло время для сборки мусора, она должна временно приостановить все потоки, пока это не будет сделано (т.е. собран мусор). Однако если поток находится на полпути в операции, которая состоит из нескольких инструкций, обращающихся н объекту в куче, а в это время сработает сборщик мусора и переместит этот объект в другое место системной памяти. ничего хорошего не произойдет. По этой причине, когда сборщик мусора приостанавливает потоки для сборки мусора, он должен подождать, попа все они не достигнут безопасной точки, когда можно будет перемещать объекты в памяти.















