Главная » Просмотр файлов » С. Мейерс - Эффективный и современный C++

С. Мейерс - Эффективный и современный C++ (1114942), страница 65

Файл №1114942 С. Мейерс - Эффективный и современный C++ (С. Мейерс - Эффективный и современный C++) 65 страницаС. Мейерс - Эффективный и современный C++ (1114942) страница 652019-05-08СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 65)

Какой в этом случае способ межпоточного сообщения яв­ляется наилучшим?Очевидный подход заключается в применении переменной условия. Если назвать за­дачу, которая обнаруживает условие, задачей обнаружения, а задачу, которая на него реа­гирует, задачей реакции, то выразить стратегию просто: задача реакции ожидает пере­менную условия, а поток задачи обнаружения выполняет ее уведомление при наступ­лении события. При-std : : condit ion variaЫe cv; / / Переменная условия событияstd: :mutex m;11 Мьютекс для использования с cvкод задачи обнаружения прост настолько, насколько это возможно:cv . notify_one ( ) ;11 Обнаружение события11 Уведомление задачи реакцииЕсли требуется уведомить несколько задач реакции, можно заменить not i f у_oneна not i f у_а 1 1 , но пока что будем считать, что у нас только одна задача реакции.Код задачи реакции немного сложнее, поскольку перед вызовом wa i t для переменнойусловия он должен блокировать мьютекс с помощью объекта std : : unique l ock.

(Бло­кировка мьютекса перед ожиданием переменной условия типична для многопоточныхбиблиотек. Необходимость блокировки мьютекса с помощью объекта std : : unique_ lockявляется частью API С++ 1 1 .) Вот как выглядит концептуальный подход:_1111std: : unique lock<s td: : mutex>lk (m) ;11cv . wait (lk) ;1111111111Подготовка к реакцииОткрытие критического разделаБлокировка мьютексаОжидание уведомления;неверно !Реакция н а событие(m заблокирован)Закрытие критического раздела ;7.5. П рименяйте ф ьючерсы void дnя однора э овых сообщений о событиях26511111111разблокирование m спомощью деструктора l kПродолжение реакции(m разблокирован)Первой проблемой при таком подходе является то, что часто называют кодом с душ­ком (code smell): даже если команда работает, что-то выглядит не совсем верным. В нашемслучае запах исходит от необходимости применения мьютексов. Мьютексы используютсядля управления доступом к совместно используемым данным, но вполне возможно, чтодля задач обнаружения и реакции такой посредник не требуется.

Например, задача обна­ружения может отвечать за инициализацию глобальной структуры данных, которая за­тем передается для использования задаче реакции. Если задача обнаружения никогда необращается к структуре данных после ее инициализации и если задача реакции никогдане обращается к ней до того, как задача обнаружения укажет, что структура данных го­това к использованию, эти две задачи оказываются не связанными логикой программыодна с другой. При этом нет никакой необходимости в мьютексе.

Тот факт, что подходс использованием переменной условия требует применения мьютексов, оставляет трево­жащий запашок подозрительного дизайна.Даже если пропустить этот вопрос, все равно остаются две проблемы, которым, опре­деленно, следует уделить внимание.•Если задача обнаружения уведомляет переменную условия до вызова wai t зада­Чтобы уведомление переменной условияактивизировало другую задачу, эта другая задача должна находиться в состоянииожидания переменной условия. Если вдруг задача обнаружения выполняет уведом­ление до того, как задача реакции выполняет wai t, эта задача реакции пропуституведомление и будет ждать его вечно.чей реакции, задача реакции "зависнет''.•Вызов wait приводит к ложным пробуждениям. В потоковых API (во многих язы­ках программирования, не только в С++) не редкость ситуация, когда код, ожидаю­щий переменную условия, может быть пробужден, даже если переменная условияне была уведомлена.

Такое пробуждение называется ложным пробуждением (spuriouswakeup). Корректный код обрабатывает такую ситуацию, проверяя, что ожидаемоеусловие в действительности выполнено, и это делается первым, немедленно послепробуждения. API переменных условия С++ делает это исключительно простым,поскольку допускает применение лямбда-выражений (или иных функциональныхобъектов), которые проверяют условие, переданное в wa it. Таким образом, вызовwai t в задаче реакции может быть записан следующим образом:cv . wait ( l k,[ ] { return Црохэошло.1111собы!1'хе;});Применение этой возможности требует, чтобы задача реакции могла выяснить,истинно ли ожидаемое ею условие. Но в рассматриваемом нами сценарииожидаемым условием является наступление события, за распознавание которого266Глава 7.

Параллельные вычисленияотве'lает поток обнаружения. Поток реакции может быть не в состоянии определить,имело ли место ожидаемое событие. Вот почему он ожидает переменную условия!Имеется много ситуаций, когда сообщение между задачами с помощью переменнойусловия вполне решает стоящую перед программистом проблему, но не похоже, что пе­ред нами одна из них.Многие разработчики используют совместно используемый булев флаг. Изначальноэтот флаг имеет значение false. Когда поток обнаружения распознает ожидаемое собы­тие, он устанавливает этот флаг:std : : atomic<bool> flag ( fa l se ) ; / /1111flagtrue;11=Совместно используемый флаг ;std : : atomic см .

в разделе 7 . 6Обнаружение событияСообщение задаче обнаруженияСо своей стороны поток реакции просто опрашивает флаг. Когда он видит, что флагустановлен, он знает, что ожидаемое событие произошло:while ( ! flag) ;/ / Подготовка к реакции11 Ожидание события11 Реакция на событиеЭтот подход не страдает ни одним из недостатков проекта на основе переменной ус­ловия. Нет необходимости в мьютексе, не проблема, если задача обнаружения устанавли­вает флаг до того, как задача реакции начинает опрос, и нет н ичего подобного ложнымпробуждениям.

Хорошо, просто замечательно.Куда менее замечательно выглядит стоимость опроса в задаче реакции. Во время ожи­дания флага задача, по сути, заблокирована, но продолжает выполняться. А раз так, оназанимает аппаратный поток, который мог бы использоваться другой зада•1ей, требуетстоимости переключения контекста при каждом начале и завершении выделенных по­току временных промежутков и заставляет работать ядро, которое в противном случаемогло бы быть отключено для экономии энергии. При настоящей блокировке задача неделает ничего из перечисленного. Это является преимуществом подхода на основе пере­менных условия, поскольку блокировка задачи при вызове wait является истинной.Распространено сочетание подходов на основе переменных условия и флагов.

Флагуказывает, произошло ли интересующее нас событие, но доступ к флагу синхронизированмьютексом. Поскольку мьютекс предотвращает параллельный доступ к флагу, не требуется,как поясняется в разделе 7.6, чтобы флаг был объявлен как std : : atomic; вполне достаточ­но простого bool. Задача обнаружения в этом случае может имеет следующий вид:std : : coпdition variaЫe cv;std : : mutex m;Ьоо l flag ( fa l se ) ;11 Как и ранее11 Не std : : atomic11 Обнаружение событияstd: : lock guard<std : : mutex> g (m) ; 11 Блокировка m_11 конструктором g7.5. П рименяйте фьючерсы void для одноразовых сообщений о событиях267flagtrue;cv . notify_one ( ) ;111111111111Сообщаем задаче реакции( часть 1 )Снятие блокировки mдеструктором gСообщаем задаче реакции( часть 2 )А вот задача реакции:1 1 Подготовка к реакции/ / Как и ранееstd: : unique_lock<std : : mutex> lk (m) ; / / Как и ранееcv .

wait(lk , [ ] ( return flag; } ) ;/ / Применение лямбда/ / выражения во избежание1 1 ложных пробуждений/ / Реакция на событие1 1 (m заблокирован)11 Продолжение реа кции1 1 (m разблокирован)Этот подход позволяет избежать проблем, которые мы обсуждали. Он работает неза­висимо от того, вызывает ли задача реакции wai t до уведомления задачей обнаружения,он работает при наличии ложных пробуждений и не требует опроса флага. Тем не ме­нее душок остается, потому что задача обнаружения взаимодействует с задачей реакцииочень любопытным способом. Уведомляемая переменная условия говорит задаче реак­ции о том, что, вероятно, произошло ожидаемое событие, но задаче реакции необходимопроверить флаг, чтобы быть в этом уверенной.

Установка флага говорит задаче реакции,что событие, определенно, произошло, но задача обнаружения по-прежнему обязана уве­домить переменную условия о том, чтобы задача реакции активизировалась и проверилафлаг. Этот подход работает, но не кажется очень чистым.Альтернативный вариант заключается в том, чтобы избежать переменных условия,мьютексов и флагов с помощью вызова wai t задачей реакции для фьючерса, установ­ленного задачей обнаружения. Это может показаться странной идеей.

В конце концов,в разделе 7.4 поясняется, что фьючерс представляет принимающий конец канала связиот вызываемой функции к (обычно асинхронной) вызывающей функции, а между зада­чами обнаружения и реакции нет отношений "вызываемая-вызывающая': Однако в раз­деле 7.4 также отмечается, что канал связи, передающий конец которого представляетсобой s t d : : promise, а принимающий - фьючерс, может использоваться для большего,чем простой обмен информацией между вызываемой и вызывающей функциями. Такойканал связи может быть использован в любой ситуации, в которой необходима передачаинформации из одного места вашей программы в другое.

В нашем случае мы воспользу­емся им для передачи информации от задачи обнаружения задаче реакции, и информа­ция, которую мы будем передавать, - о том, что произошло интересующее нас событие.268Глава 7. Параллельные вычисленияПроект прост. Задача обнаружения имеет объект s t d : : promise (т.е. передающийконец канала связи), а задача реакции имеет соответствующий фьючерс. Когда задачаобнаружения видит, что произошло ожидаемое событие, она устанавливает объектs t d : : promise (т.е. выполняет запись в канал связи).

Тем временем задача реакции вы­полняет вызов wait своего фьючерса. Этот вызов wait блокирует задачу реакции до техпор, пока не будет установлен объект std : : promise.И std : : promise, и фьючерсы (т.е. std : : future и std : : shared_ future ) являются ша­блонами, требующими параметр типа. Этот параметр указывает тип данных, передавае­мый по каналу связи. Однако в нашем случае никакие данные не передаются. Единствен­ное, что представляет интерес для задачи реакции, - что ее фьючерс установлен.

Характеристики

Тип файла
PDF-файл
Размер
12,67 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6439
Авторов
на СтудИзбе
306
Средний доход
с одного платного файла
Обучение Подробнее