Г. Шилдт - С#4.0 Полное руководство (1160795), страница 174
Текст из файла (страница 174)
Я егьа р)гоге, у которого имеется несколько конструкторов. Ниже приведена простейшая форма конструктора данного класса: ри)згзс Яеварпоге(гас зп1сха1соилс, ьпс ~пакзтлсоипс) где Тп1сла1Соип С вЂ” это первоначальное значение для счетчика разрешений семафора, т.е. количество первоначально доступных разрешений; шахйтишСоип à — максимальное значение данного счетчика, т.е. максимальное количество разрешений, которые может дать семафор. 868 Часть!).
Библиотека С№ Семафор применяется таким же образом, как и описанный ранее мьютекс. В целях получения доступа к ресурсу в коде программы вызывается метод Хафгопе () для семафора. Этот метод наследуется классом ЯешарЬоге от класса Ха1СНапг)1е. Метод Хафгопе () ожидает до тех пор, пока не будет получен семафор, для которого он вызывается.
Таким образом, он блокирует выполнение вызывающего потока до тех пор, пока указанный семафор не предоставит разрешение на доступ к ресурсу. Если коду больше не требуется владеть семафором, он освобождает его, вызывая метод Не1еазе () . Ниже приведены две формы этого метода. риЬ11с гпс Ке1еазе() риЫ1с гпс яе1еазе(гпс ге1еазеСоипг) В первой форме метод йе1еазе () высвобождает только одно разрешение, а во второй форме — количество разрешений, определяемых параметром ге1еазесоипс. В обеих формах данный метод возвращает подсчитанное количество разрешений, существовавших до высвобождения.
Метод хаьсопе () допускается вызывать в потоке несколько раз перед вызовом метода Не1еазе () . Но количество вызовов метода Хаьгопе () должно быть равно количеству вызовов метода Не1еазе () перед высвобождением разрешения. С другой стороны, можно воспользоваться формой вызова метода Не1еазе (1пг пит), чтобы передать количество высвобождаемых разрешений, равное количеству вызовов метода ХаЕСОпе().
Ниже приведен пример программы, в которой демонстрируется применение семафора. В этой программе семафор используется в классе МуТЬгеас( для одновременного выполнения только двух потоков типа муТЬгеаб. Следовательно, разделяемым ресурсом в данном случае является ЦП. Использовать семафор. изгпд Яуагеш! изгиб Яузсеш.тпгеаг(гард Этот поток разрешает одновременное выполнение // только лвух своих экземпляров. с1азз Мутпгеаг( ( риЬ11с Тпгеаг) Тпгеб у/ Здесь создается семафор, даюший только два // разрешения из двух первоначально имеюшихся. згас1с Яешарпоге зеш = пеи Яешарпоге(2, 2); риЬ11с Мутпгеас((зсггпс паве) ( Тпгг( = пен Тпгеаи(ГЬ1з.яип); Тпги.каше = паше; Тпгг).зсагс О; ) Точка входа в поток.
чо1г) аип() ( сопзо1е.хг1геььпе(тьги.наше + " ожидает разрешения."); зеш.иаьгппе()г Сопво1е.иг1геььпе(ТПгб.наше + " получает разрешение.") Гол(сьаг сь= Л ; сь < О; сьт+) Сопяо1е.ил1веЬ1пе(тьгб.наше + " : " т сп + " Тпгеаб.Б1еер(500)г ) Сопяо1е.игггеь1пе(тьтб.наше + " высвобождает разрешение."); О Освободить семафор. яеш.ве1еаяе(); ) с1аяя Бешарьогебешо ( вваггс чопб Мага() ( Сконструировать три потока.
Мутбгеаб шг1 = пен Мутьхеаб("Поток т1") Мутбгеаб шв2 = лен Мутьгеаб("Поток ((2") Мутьгеаб шСЗ = пеи Мутьгеаб("Поток ()3") шг1.ТПхб.до1п()Г шв2,ТПхб.зо1п()г шСЗ.ТПгб.ло1п()г ) ) В классе Мути геас( объявляется семафор зеш, как показано ниже. япаС1с Бешарьоге яеш = пен Бешарьоге(2, 2); При этом создается семафор, способный дать не более двух разрешений на доступ к ресурсу из двух первоначально имеющихся разрешений. Обратите внимание на то, что выполнение метода МуТЛгеас(. Ппп () не может быть продолжено до тех пор, пока семафор яеш не даст соответствующее разрешение.
Если разрешение отсутствует, то выполнение потока приостанавливается. Когда же разрешение появляется, выполнение потока возобновляется. В методе 1п Мауп () создаются три потока. Но выполняться могут только два первых потока, а третий должен ожидать окончания одного из этих двух потоков. Ниже приведен результат выполнения рассматриваемой здесь программы, хотя у вас он может оказаться несколько иным.
Поток Поток Поток Поток Поток Поток Поток Поток Поток Поток Поток Поток Глава 23. Многопоточное программирование. Часть первая: основы 869 ((1 ожидает разрешения. 41 получает разрешение. ()1: А $2 ожидает разрешения. Ф2 получает разрешение. $2 . "А ГЗ ожидает разрешения. $1: В ()2: В ()1: С $2: С $1 высвобождает разрешение. 870 Часть П. Библиотека С(г ВЗ получает разрешение. вз: к ()2 высвобождает разрешение. ()3: я ()3 ()3 высвобождает разрешение. Поток Поток Поток Поток Поток Поток Семафор, созданный в предыдущем примере, известен только тому процессу, который его породил. Но семафор можно создать и таким образом, чтобы он был известен где-нибудь еще.
Для этого он должен быть именованным. Ниже приведены формы конструктора класса Еетарбосе, предназначенные для создания такого семафора. роЬ11« яешарпосе(гп« гпт«та1Соип«, Ьп« шахтшошСоип«, я«сспЧ имя) роЬььс 5ешарпосе(сп« гп1«1а1Соип«, сп« шахтиотСоип«, я«тьпэ имя, оо« Ъоо1 стеа«епхеы) Применение событий Для синхронизации в С(( предусмотрен еще один тип объекта; событие. Существуют две разновидности событий: устанавливаемые в исходное состолние вручную и автоматически. Они поддерживаются в классах Маппа1реяеСЕуепС и )(и«брезе«Еуеп« соответственно.
Эти классы явллютсч производными от класса Еуеп«Хат«иапо)1е, находящегося на верхнем уровне иерархии классов, и применяются в тех случаях, когда один поток ожидает появления некоторого события в другом потоке. Как только такое событие появляетсл, второй поток уведомляет о нем первый поток, позволяя тем самым возобновить его выполнение. Ниже приведены конструкторы классов маппа1ееяесеуепс и )(псоееяесеуепс. роь11с мапоа1кеяесеуепс(ьоо) тпгсга15«а«е) робгто Ко«одевееяуеп« (Ьоог гпл«га15Саее) Если в обеих формах параметр 1п1 сга15«а се имеет логическое значение с сне, то о событии первоначально уведомляется. А если он имеет логическое значение Са1яе, то о событии первоначально не уведомляется. Применяются события очень просто. Так, для события типа Маппа1реяе«Еуепс порядок применения следующий.
Поток, ожидающий некоторое событие, вызывает метод иа1«опе () для событийного объекта, представляющего данное событие. Если собьпийный объект находитсл в сигнальном состоянии, то происходит немедленный В обеих формах имя обозначает конкретное имя, передаваемое конструктору. Если в первой форме семафор, на который указывает имя, еще не существует, то он создается с помощью значений, определяемых параметрами Зпх «га1соип с и шаххшишсоип с. А если он уже существует, то значения параметров 1п1 «1 а 1 со оп с и тахяшишсоип с игнорируются.
После возврата из второй формы конструктора параметр сгеа сег(ыем будет иметь логическое значение сгпе, если семафор был создан. В этом случае значения параметров т п1 Сга1 Со оп С и шахяшишСопп С используются для создания семафора. Если же параметр ссеа Сес(Ыем будет иметь логическое значение га1яе, значит, семафор уже существует и значения параметров 1п1 «1а1Соип С и шахгшишСопп С игнорируются.
Существует и третья форма конструктора класса Бешарбо «е, в которой допускается указывать управляющий доступом объект типа Еешарбосеэеопсссу. С помощью именованных семафоров можно синхронизировать взаимодействие процессов. Глава 23. Многопоточное программирование. Часть первая: основы 871 возврат из метода Ма1СОпе () . В противном случае выполнение вызывающего потока приостанавливается до тех пор, пока не будет получено уведомление о собь)тии. Как только событие произойдет в другом потоке, этот поток установит событийный объект в сигнальное состояние, вызвав метод Бес () .
Поэтому метод Бес () следует рассматривать как уведомляющий о том, что событие произошло. После установки событийного объекта в сигнальное состояние произойдет немедленный возврат из метода Иа1СОпе (), и первый поток возобновит свое выполнение. А в результате вызова метода Ееяеб () событийный объект возвращается в несигнальное состояние. Событие типа йптонеяеСЕчепб отличается от события типа Маппа1неяеСЕчепс лишь способом установки в исходное состояние. Если для события типа Маппа1пеяеСЕчепс событийный объект остается в сигнальном состоянии до тех пор, пока не будет вызван метод невес (), то для события типа йпсопеяесЕчепс событийный объект автоматически переходит в несигнальное состояние, как только поток, ожидающий это событие, получит уведомление о нем и возобновит свое выполнение. Поэтому если применяется событие типа АпсонеяеСЕчепс, то вызывать метод невес () необязательно.
В приведенном ниже примере программы демонстрируется применение события типанаппа1пеяеСЕчепс. // Использовать событийный объект, устанавливаемый // в исходное состояние вручную. паапа Яузгев; чз1пд Буятев.ТПтеабгпсы // Этот поток уведомляет о том, что событие передано его конструктору. с1аяя МуТПгеаб ( рчб11с Тьгеа<) Тлгс)," Напча1аеяетечепт вге; рч)з11с МУТПгеаб(ятт1пч паве, Маппа1аеяетвчепт ечс) тпгб = пен тлтеап(гп1я.пчп)г Тлгб.наше = паве," вте = ечт; Тлгб.ятагт()Г ) // Точка входа в поток. чпьс( Ппп() ( Сппяо1е.иггтяьгпе("Внутри потока " + Тлгп.наше)г гог(гпг г=б; 1<5; 1++) ( Сопяо1е.иг1теъгпе(тпгб.наше); Тлгеаб.51еер(500)г ) сопяо1е.хг1геьгпе(тпг<).маше + " завершен!")г // Уведомить о событии.
вте.зег(); 872 Часть 11. Библиотека б№ с1аяя Мапиа1Енепяпешо ( яяая1с чо1б Ма1п() ( Мапиа1неяескчепя ечСОЬЗ = пен Маппа1аеяеявчепя(тя1яе) Мутпгеаб шя1 = пен Мутбгеаб("Событийный Поток 1", енСОЬЗ); Сопяо1е.игьяеъьпе("Основной поток ожидает событие.") О Охмдать уведомления о событии.
ечСОЬЗ.Хагяопе(); Сопяо1е.Хгьяеъьпе("Основной поток получил "уведомление о событии от первого потока.") О Установить событийный объект в исходное состояние. енСОЬ).Везет(): шя1 = пен Мутьгеаб("Событийный Поток 2", ечЯОЬЗ)г О Ожилать уведомления о событии. енСОЪ).иаьяопе()г Сопяо1е.Хг1теъьпе("Основной поток получил " + "уведомление о событии от второго потока."); Ниже приведен результат выполнения рассматриваемой здесь программы, хотя у вас он может оказаться несколько иным.