Глава 1 Базовый Синтаксис ; День 36 ; 36.2
Summary
TLDRВ этом видео учитель Сергей продолжает курс по многопоточному программированию на C++. Он объясняет, как использовать мьютексы для синхронизации потоков и защиты разделяемых данных. В видео рассматривается проблема совместного использования ресурсов и как с ее помощью можно решить с помощью мьютексов. Также Сергей вводит Lock Guard, который автоматически захватывает и освобождает мьютекс, предотвращая возможные ошибки. Он демонстрирует, как правильно разделять синхронизованный и асинхронный код, чтобы достичь оптимального использования многопоточности и улучшить производительность программы.
Takeaways
- 🔒 В видео рассматривается проблема синхронизации потоков и использование мьютексов для защиты разделяемых ресурсов.
- 👨🏫 В плейлисте есть уроки о потоках и мьютексах, которые рекомендуется изучить для лучшего понимания темы.
- 📚 Создание мьютекса (MTX) позволяет контролировать доступ к критической секции кода, обеспечивая, что только один поток может работать с ней одновременно.
- 🔄 Примеры в видео демонстрируют, как несинхронизированные потоки могут привести к некорректному выводу данных, например, на консоль.
- ⏱️ В видео показано, что использование мьютексов может снизить производительность программы, так как потоки будут ожидать доступ к защищенным ресурсам.
- 📐 В качестве примера синхронизации потоков используются функции рисования геометрических фигур в консоли.
- 🔄 Демонстрирован эффективный многопоточный подход, который показывает, как части кода могут выполняться в многопоточном режиме, в то время как критические секции защищены мьютексами.
- 🛠️ В видео рассматривается использование Lock Guard для автоматической блокировки и разблокировки мьютекса при входе и выходе из области видимости.
- 👀 Автор подчёркивает важность корректного использования мьютексов и Lock Guard для предотвращения ошибок и проблем с производительностью.
- 🔑 В заключение, видео подчёркивает преимущества использования библиотеки STL и стандартных шаблонов для эффективного многопоточного программирования.
Q & A
Что означает аббревиатура 'МТЭК' в контексте многопоточного программирования?
-В контексте многопоточного программирования 'МТЭК' означает 'мьютекс' (mutex), который используется для синхронизации потоков и защиты разделяемых данных.
Какие проблемы могут возникнуть при работе с несинхронизированными потоками?
-При работе с несинхронизированными потоками могут возникнуть проблемы с разделяемыми ресурсами, например, консоль, что может привести к нарушению целостности данных и некорректному выводу.
Что такое 'Lock Guard' в многопоточном программировании на C++?
-'Lock Guard' - это класс, который захватывает мьютекс в своем конструкторе и освобождает его в деструкторе, гарантируя автоматическое управление блокировкой и разблокировкой.
Какие есть методы для управления мьютексом в объекте типа 'MTX'?
-В объекте типа 'MTX' используются методы 'lock' и 'unlock' для управления доступом к защищенным ресурсам.
Почему важно использовать 'Lock Guard' при работе с мьютексами?
-Использование 'Lock Guard' важно для автоматического освобождения мьютекса после завершения защищенной секции кода, что предотвращает возникновение ошибок, связанных с забвом освободить мьютекс.
Какие есть различия между использованием мьютекса и 'Lock Guard'?
-Мьютекс используется вручную с явным вызовом методов 'lock' и 'unlock', в то время как 'Lock Guard' управляет блокировкой и разблокировкой автоматически через自己的人生ycle в конструкторе и деструкторе.
Чем может быть пример разделяемого ресурса в многопоточном программировании?
-Пример разделяемого ресурса может быть консоль, к которой могут обращаться несколько потоков для вывода информации.
Какие могут быть последствия неправильного использования мьютексов?
-Неправильное использование мьютексов может привести к нарушению синхронизации потоков, deadlock'ам или race condition, что повлияет на стабильность и корректность программы.
Что такое 'ботылочный горлышек' в контексте производительности многопоточности?
-Ботылочный горлышек - это узкое место в производительности программы, вызванное синхронизацией потоков и ограничением доступа к разделяемым ресурсам.
Как 'Lock Guard' может помочь в предотвращении ошибок, связанных с управлением мьютексами?
-'Lock Guard' может помочь, автоматически захватывая и освобождая мьютекс, что упрощает управление блокировками и уменьшает риск человеческой ошибки.
Какие задачи 'Lock Guard' выполняет в многопоточном приложении?
-'Lock Guard' выполняет задачи автоматического захвата мьютекса при создании объекта и освобождения его при уничтожении объекта, обеспечивая корректное управление доступом к разделяемым ресурсам.
Outlines
🔒 Многопоточность и синхронизация потоков
В этом параграфе рассматривается проблема синхронизации в многопоточном программировании. Автор объясняет, что для корректной работы потоков и предотвращения неконтролируемой работы с общим ресурсом, таким как консоль, необходимо использовать механизмы синхронизации. В примере кода демонстрируется, как многопоточная программа может работать некорректно без синхронизации, и как применение мьютекса (MTX) с помощью методов lock и unlock может исправить ситуацию. Также упоминается, что использование мьютекса может снизить производительность программы из-за блокировки потоков, что подтверждается экспериментальным временем выполнения кода с и без синхронизации.
👷♂️ Применение мьютекса для защиты разделяемых ресурсов
Автор продолжает тему многопоточности и рассматривает использование мьютекса для защиты разделяемых ресурсов. В видео описывается, как мьютекс может быть использован для синхронизации доступа к разделяемым данным, предотвращения одновременного доступа несколькими потоками и обеспечения целостности данных. Также рассматривается пример использования мьютекса для измерения времени выполнения программы и демонстрация влияния синхронизации на производительность. Автор подчёркивает важность использования мьютексов только в критических секциях кода, чтобы не снижать производительность многопоточности.
🛠 Алгоритм equal с бинарным предикатом в STL
В этом параграфе рассматривается использование алгоритма equal из стандартной библиотеки шаблонов (STL) в языке программирования C++. Автор объясняет, как использовать алгоритм equal с бинарным предикатом для сравнения двух коллекций, когда элементы класса не перегружают оператор сравнения. Приводится пример с классом Point и векторами此类对象, где бинарный предикат используется для сравнения объектов по полям X и Y. Также рассматривается поведение алгоритма при изменении порядка элементов и значений полей, а также рекомендуется использование отладчика для изучения работы алгоритма на примере.
🛡️ Использование Lock Guard для автоматической синхронизации
Автор представляет Lock Guard как класс, который упрощает синхронизацию потоков, захватывая мьютекс в конструкторе и освобождая его в деструкторе. В видео объясняется, что Lock Guard предотвращает ошибки, связанные с забытым освобождением мьютекса, и обеспечивает более надежную синхронизацию. Приводятся примеры использования Lock Guard для защиты разделяемых данных и демонстрация того, как он работает в многопоточном контексте. Также рассматривается влияние Lock Guard на производительность программы и примеры оптимизации с использованием области видимости объекта Guard.
🔄 Блокировка и разблокировка мьютекса с помощью Lock Guard
В заключительном параграфе автор демонстрирует преимущества использования Lock Guard для управления мьютексами в многопоточном программировании. В видео показано, как Lock Guard может быть использован для автоматической блокировки и разблокировки мьютекса, что упрощает синхронизацию и уменьшает риски ошибок. Приводятся примеры кода, где Lock Guard используется для защиты критической секции, и объясняется, как это повлияло на скорость выполнения программы. Автор также рассматривает стратегии оптимизации многопоточности, используя разграничение синхронного и асинхронного кода, и заключает урок с рекомендациями по использованию Lock Guard для автоматизации синхронизации потоков.
Mindmap
Keywords
💡мьютекс (mutex)
💡многопоточное программирование
💡синхронизация потоков
💡критическую секцию
💡Lock Guard
💡разделяемый ресурс
💡ботылочный горлышек
💡алгоритм equal
💡бинарный предикат
💡STL (стандартная библиотека шаблонов)
Highlights
Введение в многопоточное программирование и создание потоков T1 и T2 для выполнения функции Print.
Проблема несинхронизированного вывода потоков в консоль, что приводит к нечитаемым результатам.
Использование мьютекса (MTX) для синхронизации потоков и предотвращения ошибок вывода.
Объяснение методов lock и unlock для управления доступом потоков к критической секции кода.
Подчёркивание важности вызова unlock для освобождения доступа к критической секции другим потокам.
Демонстрация корректного вывода двух прямоугольников после синхронизации потоков.
Обсуждение использования двусвязного списка для совместного использования с синхронизацией потоков.
Влияние синхронизации потоков на производительность программы и время выполнения.
Показатель эффективности многопоточности при наличии долго выполняющегося кода вне критической секции.
Использование мьютекса для защиты разделяемых ресурсов, таких как двусвязный список, при многопоточном доступе.
Анализ производительности многопоточности в зависимости от использования синхронизации и защиты ресурсов.
Пример использования бинарного предиката с алгоритмом equal для сравнения двух последовательностей.
Обсуждение важности корректного сравнения объектов класса без перегрузки оператора ==.
Введение в Lock Guard как класс для автоматической синхронизации потоков с помощью мьютекса.
Объяснение того, как Lock Guard захватывает мьютекс в конструкторе и освобождает в деструкторе.
Раскрытие преимуществ использования Lock Guard для избегания ошибок при синхронизации потоков.
Демонстрация использования Lock Guard для защиты разделяемого ресурса и корректного выполнения программы.
Transcripts
и собственно выполним Ту же самую логику
но только в двух отдельных потоках У нас
есть Т1 Т2 и соответственно мы эти
потоки будем Джони к нашему основному
потоку если вы не знаете как работать с
потоками Что такое Joint Что такое детач
то советую вам посмотреть первый урок в
этом плейлисте ссылку на весь плейлист
тоже оставлю внизу описании Ну и
собственно сейчас мы всё это дело
запускаем в многопоточного режиме у нас
по сути есть Майн поток который ничего
не будет делать и создаётся ещё два
потока каждый из этих потоков будет
выполнять функцию Print и отрисовывать
наши прямоугольники только символами
передадим разные один звёздочки другой
реш запускаем смотрим Что у нас
получится у нас получилась Вот такая вот
непонятная ерунда потому что у нас
потоки не были между собой
синхронизированы и так как сейчас у нас
ресурс который используется для вывода
данных это консоль и два потока работа с
ней одновременно то есть разделяет её и
не синхронизированы между собой мы
получили вот такую вот ерунду на экран
Хотя должны были получить два разных
прямоугольника во всяком случае когда мы
запускали эти функции эту функцию вот на
потоке так и происходило так вот для
того чтобы синхронизировать работу вот
этих двух потоков чтобы решить проблему
совместного использования Ну в данном
случае консоли Но это может быть к
примеру двусвязный список какие-то
другие сложные ресурсы которы нужно
модифицировать мы должны использовать
текс мы уже с вами подключили мтек с
помощью Илю и собственно вот здесь у
меня закомментировать мтек ну по сути
это объект класса МК Называется он MTX
как он используется нам с помощью Текса
нужно указать ту секцию в нашем коде
которая должна работать только с одним
потоком чтобы текс её защищал в случае
если с ней уже работает один из потоков
и к ней попытается обратиться другой
поток текс другому потоку говорит нет
подожди сейчас этот участок кода уже
выполняется другим потоком А в тот
момент когда этот участок Куда
выполнился к разрешает другому потоку
который пытается получить доступ к этому
пому участку кода также работаеть с этим
участком как вообще всё это
реализовывается у объекта типа MX в
нашем случае MTX есть два метода loock и
Unlock Ну там где loock - это понятное
дело что доступ закрыт а там где
Unlock означает что участок кода
выполнился и теперь другой поток может
получать доступ к этому участку кода
Таким образом мы с помощью вот этого
мьютекс написали что вот отсюда до сюда
вот этот участок кода у нас одновременно
может использоваться только одним
потоком
обращаю Ваше внимание на то что
обязательно нужно вызвать мело потому
что должен дать возможность остальным
потокам знать о том что всё-таки уже
этот участок кода разблокирован его
можно использовать То есть к илок есть
ещ другие моменты с ми мы рассмотрим и
далее в других уроках но пока вот для
базового пониманием ютек это достаточно
запустим наш код сейчас и посмотрим что
у нас
получится Как видите у нас выявилось два
отдельных прямоугольника мы
синхронизирован случае нашу консоль от
совместного использования то таким образ
мы моли бы использовать двусвязный
список если бы один поток например свал
оттуда элементы другой добавлял или
удалял Ну то есть принцип тот же самый
только здесь вместо вот этого участка
кода у нас должен быть тот участок кода
который мы хотим защитить при совместном
использовании Казалось бы всё так просто
всё прекрасно работает но осталось
обратить внимание ещё на один важный
момент Давайте засе время выполнения
программ вот здесь прямо перед созданием
потоков создадим объект сий нам
достаточно его лишь создать для того
чтобы он измерил время выполнения нашей
программы о том как он работает уже
говорил у нас был отдельный урок
запустим нашу программу смотрим сколько
будет выполняться наш код мы получили 2
секунды Давайте ещ раз запустим конечно
там есть небольшая погрешность но она
для нас не столь важна Суть в том что мы
получили 2 секунды Теперь давайте
уберём синхронизацию потоков с помощью
Текса UN и посмотрим сколько теперь
будет выполняться наш код наш код
выполнялся секун Я думаю вы можете
догадаться в ЧМ подвох синхронизации
потоков Мони это узкое место в скорости
выполнения вашей программы потому что к
вот этому коду может получить доступ
только один поток но в этом же и суть
синхронизации и защиты ресурсов Это
значит что остальные потоки в это время
ничего не будут делать таким образом
сейчас у нас было два потока и если они
работают одновременно они работает одну
секунду Если мы с помощью мьютекс
защищаем вот эту логику синхронизирует
потоков мы получаем время работы в два
раза больше как будто мы вообще не
используем многопоточность наверное
кому-то из вас может прийти в голову
мысль А нафига вообще нужна тогда
многопоточность Ну если вот такая
ситуации е фактически нет Суть в том что
мы же не используем ютекс везде на всём
коде подряд а только на тех критически
важных секциях в которых должна быть
синхрони работа между потоками и на тех
ресурсах которые дож быть защищены при
совместном использовании что это
означает это означает что до вот этой
логики или после неё в нашей функции
котору мы передали в отдельный поток
могут выполняться ещ какие-то действия и
они тоже могут занимать длительный
период времени Нони к примеру не требуют
синхронизации так вот они у нас
выполнятся в много поточно режиме Вот
именно момент синхронизации Он у нас в
программе будет таким узким местом по
сути бутылочным горлышком в
производительности нашей программы
давайте рассмотрим конкретный пример
допустим представим что у нас есть
какой-то момент долго исполняемого кода
до нашей критической секции и после
нашей критической секции для того чтобы
эмулировать это долго исполняемый код я
просто буду приставить поток то есть
слить его на 2 секунды до критической
секции и после критической секции для
частоты эксперимента запустим всё это
дело в одно потоке и посмотрим Сколько
времени оно будет выполняться так вот у
нас один Принт а вот второй Принт
запускаем и
смотрим Итого наша программа
секунд теперь запустим ВС это дело в
двух потоках Обратите внимание Так как у
нас вот этот момент который долго
выполняется и вот этот момент находится
не в критической секции то есть не
защищённом ксом не синхронизируется Это
означает что вот эти вот моменты могут
выполняться одновременно в разных
потоках Это значит что мы получим
выигрыш производительности запускаем и
смотрим Сколько времени всё это дело
займёт наш код выполнился за 6 секунд а
теперь давайте уберём защиту критической
секции пусть теперь всё колба
подряд 5 секунд То есть как видите на
нашу критическую секцию уходит 1 секунда
Ну я по грубым прикидкам говорю но я
думаю вы понимаете когда мы использовали
всё это в одно потоке наш код вообще в
принципе 10 секунд выполнялся таким
образом Хотя текс и является по сути
бутылочным горлышком производительности
нашей системы потому что тическая секция
приостанавливает многопоточность Ну по
сути это так и есть всё равно мы
получаем выигрыш потому что другие
задачи на выполнение которых может
требоваться длительный период времени и
которые не требуют низации которые
например откуда-то грузят данные просто
долго они могут всё равно выполняться в
нескольких потоках и Обратите внимание
если мы к примеру модифицируем код ещё
вот так вот добавим ещё один поток
Пускай здесь будет Вот такая вот штука и
задним ещё Т3 посмотрим сколько будет
выполняться наш
код 7 секунд а если мы выполним всё это
в одном потоке то 15 секунд Мы точно
Будем ждать
так вот в одно потоке 15 секунд
многопоточности 7 секунд таким образом
ещё раз обращаю Ваше внимание что хотя
мтек и не даёт всем потокам одновременно
работать с теми ресурсами которые Он
защищает для которых нужна синхронизация
и с которыми мы не можем работать
одновременно во всех потоках всё равно
мы получаем выигрыш многопоточности но
только в тех задачах которые не требуют
такой вот защиты и синхронизации Ну и в
случае когда мы работаем с несколькими
потоками и с
разделяемых ресурсах выполняется некая
последовательность операций которая
является по сути некой транзакцией то
есть должна выполниться вся подряд
именно для того чтобы операция считалась
завершённое нам нужно использовать к и
собственно на этом У меня пока всё если
вам понравился этот урок он был для вас
полезным и интересным не забудьте
поставить лайк
под Приветствую вас друзья Меня зовут
Сергей мы с вами продолжаем изучать
библиотеку стандартных шаблонов и сталь
в языке программирования c+ Plus данный
урок является прямым продолжением
прошлого урока где мы говорили о том как
работает алгоритм equal и алгоритм Miss
Match Поэтому если вы его не видели то
рекомендую начать просмотр именно с него
ссылка внизу в описании и собственно в
том уроке Я обещал что расскажу Каким
образом мы можем использовать вместе с
алгоритмом equal бинарный предикат
собственно Вот именно этим мы сегодня и
займёмся Не забудьте поставить лайк под
этим видео если вам интересны уроки о
библиотеке стандартных шаблонов stl Ну и
собственно продолжим теперь рассмотрим
Как использовать алгоритм equal с
предикатом Обратите внимание я писал
простой clp который отображает две точки
в пространстве пос X и Y Ну как геометр
я думаю вы помните этот пример Я
показывал его уже в прошлых уроках здесь
у нас есть конструктор который принимает
два эти поля X и Y и инициализирует
собственно эти поля в конкретном
экземпляре класса У нас есть два вектора
типа Point которые я так и оставил с
названием Error и Error но теперь они
содержат по три объекта класса Point в
данном случае у нас эти три объекта и в
том и в том векторе идентичны Обратите
внимание сейчас если я собираю проект мы
получаем ошибку при компиляции Проблема
в том что я специально не
переопределить если бы он был
переопределить И вот такую вот обычную
логику алгоритма equal этот алгоритм
просто бы использовал этот оператор в
сравнения но в том случае если вы хотите
использовать с алгоритмом equal какой-то
В класс в котором такого оператора
сравнения нету либо же хотите сравнивать
этот класс по какой-то именно своей
логике которая реализована не так как в
операторе сравнения вам нужно
использовать предикат собственно что мы
сейчас и будем делать если вы не помните
что такое предикаты и анонимные функции
то нужные ссылки найдёте внизу в
описании под этим видео А мы продолжим
Итак следующим параметром после того как
мы указали начало конец первой коллекции
начало конец Второй коллекции у нас идёт
тот самый предикат который позволит нам
сравнить каким-то образом эти две
коллекции так как захотим мы это у нас
бинарный предикат который должен
принимать два параметра и собственно это
у нас будет два объекта класса
Point P1 и P2 принимаем эти параметры по
ссылке потому что нам не нужно будет
копировать весь объект А мы можем просто
обратиться по адресу в памяти чтобы
посмотреть что Что там находится а
константные ссылки - Это для того чтобы
мы сами себя
обезопасит выполнения алгоритма equal и
обработки нашей логики и собственно наш
бинарный предикат должен возвращать
какое-либо логическое булевое значение
определим здесь переменную в которой
будем хранить этот результат и её мы
будем возвращать в эту переменную мы
должны присваивать результат сравнения
наших двух входящих объектов и в данном
случае мы можем сами выбирать как мы
будем сравнивать ну к примеру мы можем
реализовать именно ту логику которая
ожидается от нас в перегружено операторе
то есть здесь мы проверяем на равенство
два поля что поля X между объектом P и
P2 равны между собой и поля Y тоже между
ними равны Таким образом мы сравниваем
две точки конкретно по двум полям и в
случае если эти объекты равны У нас вот
здесь в БМ результате будет Т И мы
вернём этот результат на самом деле эта
переменная нам здесь не нужна мы можем
возвращать сразу результат сравнения
этих полей так как нам хочется в данном
случае если мы сейчас запустим нашу
программку мы получим единичку потому
что у нас объекты класса Point которые
являются элементами двух коллекций
находятся в идентично порядке и имеет
идентичные значение полей если мы к
примеру один поит например в первом
векторе смести в другом порядке мы
получим уже результат fse но это как тот
же самый пример целыми числами если у
нас две последовательности содержат
одинаковые элементы Но они в разных
индексах то алгоритм и считает что это
разные последовательности и нам
предварительно необходимо такие
последовательности отсортировать вернём
как было Сейчас если мы запускаем у нас
опять-таки две эти последовательности
равны мы получаем единицу А если мы к
примеру изменим значение какого-то Из
полей вот к примеру в первом поинте в
первом поит первой коллекции поменяем
значение новой с поля мы уже опять-таки
получим значение ноль собственно для
того чтобы понять действительно Как это
работает необходимо посмотреть в
отладчике Ну это в принципе такой вот
закон если хотите хорошо разбираться что
как работать смотрите в отладчике или же
если хотите решить какую-то проблему
Итак у нас имеется две коллекции рр
которая содержит три точки вот они есть
коллекция ror2 которая также содержит
три точки Вот она две разные коллекции
содержат абсолютно идентичные объекты
класса и в одном и том же порядке
поэтому алгоритм equal рассмотрит их как
идентично у нас точка установлена
девяносто пятой строчке кода и Сейчас мы
посмотрим как будет обрабатывать
алгоритм и эти объекты Итак у нас первая
итерация по сути мы проверяем вот эти
вот два объекта проверяет у нас эти
объекты предикат которые мы написали он
принял эти два первых объекта
параметрами и мы сравниваем их поля у
объекта p1x равен 1 у объекта p2x раве 1
то есть по полям X они уже равны и мы
проверяем опять-таки эти объекты по
полям Y у первого объекта - это три и у
второго три То есть соответственно вот
эти два объекта у нас уже равны делаем
ещё шаг у нас вторая итерация сейчас мы
проверяем вот эти объекты то есть по
сути алгоритм просто перебирает две
последовательности и сравнивает их
объекты вот сейчас это уже вторая то с
им 4 и иреком пятёркой второй объект у
нас идентичный сравнивает их поля и
соответственно алгоритм и на основе
этого сравнения выносит решение равны
объекты или нет X4 X4 у двух разных
объектов P1 P2 Y тоже идентичный Ну и
третья операция - это вот эти вот уже
объекты Ну я думаю вы поняли что раз мы
сравниваем по всем полям объекты которые
у нас идентичны в обоих коллекциях то
соответственно наш алгоритм Ил вернул
значение тру если мы изменим порядок
этих объектов или просто по одному и
тому же индексу будут объекты с
различными полями вот к пример мы здесь
двойку уже кнм и запустим опять-таки наш
алгоритм смотрите что у нас получится мы
уже на первую итерацию гда будем
сравнивать вот эти вот два объекта
получим их вот сюда в параметры P1 у нас
X = 1 y = 2 а P2 Y = 1 Y = 3 то есть вот
эта вот логика которая будет сравнивать
у нас по полям уже вернёт флс здесь X1 и
здесь X1 А здесь y = 2 а здесь Y = 3 то
есть это разные объекты вот эта вот
логика вернёт fse соответственно
алгоритм equal уже поймёт что эти
контейнеры не одинаковы и как результат
мы получим fse Ну вот таким вот образом
собственно работает алгоритм equal с
бинарным предикатом и на этом У меня на
сегодня всё Если вам понравилось это
видео оно было для вас полезным
интересным не забудьте поставить под ним
лайк от этого зависит
раз вас друзья Меня зовут Сергей мы с
вами продолжаем изучение многопоточного
программирования в языке c+ Plus
сегодняшний урок У нас будет прямым
продолжением прошлого урока где мы
говорили о мьютекс о защите разделяемых
данных и синхронизации потоков и сегодня
мы будем говорить о такой конструкции
как Lock Guard для чего это вообще нужно
как это использовать Друзья если вам
интересна тема многопоточного
программирования то не забудьте
поддержать это видео лайком Ну и
собственно приступим к Теме нашего урока
Итак Lock Guard - это класс задачей
которого является захватить ютекс в
конструкторе при создании объекта такого
класса и освободить этот текс в
деструктор в тот момент когда объект
этого класса будет покидать какую-либо
область видимости То бишь по сути в
момент создания объекта класса lck Guard
он вызывает вот эту штуку а в тот момент
когда этот объект уничтожается в
деструктор вызывается вот эта штука для
чего это нужно и как это используется в
прошлом уроке мы с вами выяснили что
ютекс сам по себе Нам нужен для того
чтобы синхронизировать потоки и защитить
какой-то разделяемый участок кода между
несколькими потоками для того чтобы
какая-то определённая последовательность
действий выполнила с транзакций и у нас
даже был пример с распечатывания
геометрических фигур в консоли с помощью
разных потоков в данном случае у нас
здесь консоль выступает разделяемый
ресурсом которые делится между
несколькими потоками так вот если мы вот
этот момент работы с консолью защищаем с
помощью лока мы получаем корректную
работу нашей программы то есть в данном
случае у нас три потока отрисовывать Т
геометрические фигуры всё отработала
корректно если мы Лок убираем то есть не
защищаем эту критически важную секцию с
разделяемый ресурсами получаем вот такую
вот непонятную ерунду то есть
целостность данных у нас нарушена так
вот важной особенностью при работе с
мьютекс является что нам нужно указать
конкретно вот секцию которую мы защищаем
и в которой будет поток
синхронизироваться с помощью методов L и
Unlock в тот момент когда один из
потоков добирается до вот этой
конструкции вызывается метод Лок то
другие потоки добравшись до этой же
конструкции дальше пойти не могут аж до
того момента пока первый поток который
захватил тек не выполнит весь этот код
не доберётся до вот этой его строчки
кода и не освободит к и только после
этого какой-то другой поток сможет
захватить ВК и также выполнить этот код
Ну и собственно так между всеми потоками
так вот что будет если мы к примеру
когда будем писать наш код случайно
забудем вот этот момент по сути что мы
сдела мы сказали что поток который
выполняет функцию Print захватывает к
выполняет код но никогда не освобождает
этот к это будет означать что остальные
потоки так и будут не скончания времён
ожидать покажем текс освободится Как
видите у нас есть три потока каждый
поток рисует свою фигуру но отрисовать
только одна фигура Потому что первый
поток который успел захватить в к
выполнил этот код но КС так и не
освободил также ничего хорошего не
выйдет в том случае если мы забудем к
примеру вот эту часть кода то есть мы не
заблокирую текс Ну во-первых все потоки
сразу же получат доступ к тому участку
хода который мы хотели по идее защитить
и во-вторых каждый из этих мкв каждый из
этих потоков попытается выполнить метод
Ало Текса то есть разблокировать его
хотя он до этого не был залоченный
закрытый и соответственно благодаря
этому мы тоже получим ошибку так вот
собственно для того чтобы вот такой вот
проблемы избегать случайной вот такой
вот ошибки нам и нужен Guard таким
образом между вызова вот этих двух
методов Unlock мы можем использовать тот
самый Давайте создадим объект такого
класса мы должны указать ему тип данных
с которым он будет работать это и далее
при создании объекта этого Гарда мы
должны вот тот самый к который мы
создавали для синхронизации наших
потоков передать ему рут таким образом
вот этот loog Guard выполнит сам за нас
вот те операции Log и Unlock Давайте
посмотрим как это всё произойдёт а затем
более подробно поговорим То есть как
видите у нас сейчас все наши потоки
синхронизированы именно в области нашей
функции Print я уже говорил что задача
Log Guard захватить к в конструкторе
освободить его в деструкторы так как
захват мтек сов происходит в
конструкторе а конструктора
соответственно у нас вызывается при
создании объекта то вот в этот момент
когда вы создаёте объект типа lard
считайте что вы написали MX Log вторым
важным моментом является тогда когда у
этого объекта ard вызове деструктор в
данном случае дестру У нашего объекта
Guard который является типом Guard
вызове в момент тогда когда вот этот
объект будет выходить из области
видимости этой функции Print таким
образом вот э вот наша вся функция Print
благодаря тому что в ней просто в момент
её вызова найперше операции которая
происходит является создание объекта
типа lard то этой функция и является
защищённой с помощью тек то есть
различные потоки могут получать к ней
доступ лишь по очереди не все
одновременно если мы вот сейчас за
комментируем этот момент созданием
объекта типа lard то мы получим эту
ситуацию Когда у нас была без
синхронизации если у нас функция должна
быть полностью синхронизирована То есть
все действия которые выполняются в ней
должны быть только через utex все
операции должны быть защищены то
использование Log для нас идеальный
вариант потому что мы точно не забудем
залочить ютекс и затем не забудем его
освободить потому что за нас это сделает
вот этот объект lard прямо в своём
конструкторе и в деструкторы но я думаю
вы помните что тот код который
используется вместе с мтек то есть
защищённая область которая используется
для синхронизации потоков она по сути
полностью выполняется в одно поточно
режиме потому что другие потоки по
понятным причинам потому что для этого
используется мтек не могут работать с
этими же данными в тот же самый момент а
так вот если мы хотим в этой же функции
использовать какие-то моменты которые
должны работать в многопоточного режиме
тогда нам уже с лордом работать не
настолько удобно но тем не менее это
тоже решаемо И как вы помните у нас был
ещё вот такой пример что у нас в начале
вызова функции Print и в конце вызова
функции Print слипался наш поток то есть
приостанавливается на 2 секунды для того
чтобы эмулировать какую-то трудную и
долгую задачу В этом же методе но
которое не требует синхронизации То есть
то что можно было не лочи с помощью
Текса но в случае с мтек сом мы вот вот
этим Так мы просто берём и указываем что
я вот хочу вот эту область залочить
здесь освободить и по сути вот этот код
у нас будет выполняться синхронно А вот
этот вот эти два слипа асинхронно Ну то
есть там как минимум на каждую функцию
Print будет 4 секунды она должна
выполниться три раза если в одно поточно
режиме то это уже 12 секунд плюс ещё вот
эта операция Но если вы многопоточности
то вот этот момент и вот этот момент
может выполняться одновременно во всех
потоках и только вот этот момент
маленький участок кода выполняется
синхронно Таким образом мы всё равно в
производительности выигрываем Но я это
всё показывал в прошлом уроке поэтому
рекомендовал вам его посмотреть таким
образом смотрите общее время выполнения
программы 7 секунд Хотя если посчитать
однопоточный режим Да сколько
выполняется функция Print опять-таки это
ну 12 секунд плюс ещё вот этот код Ну то
есть там как минимум 15 секунд будет мы
в прошлый раз измеряли так вот к чему
это всё рассказывал к тому что если мы
используем Unlock мы легко можем указать
вот просто конкретную область которую
нам нужно синхронизировать в случае если
мы работаем с лордом Ну да допустим там
где нам нужен ло мы просто создаём
объект Guard Как нам указать ему Где нам
нужно чтобы он уничтожил И тем самым
вызвал свой
деструктор там где нам нужно разлочить
тот код там где нужно его освободить
потому что Вот в такой реализации
получается что вот эта вот часть кода у
нас будет выполняться в нескольких
потоках потому что она не защищена мтек
сам лордом а вот всё что ниже будет уже
работать в синхронном режиме и даже вот
эта вот часть которая по идее у нас
могла бы выполняться в разных потоках
одновременно потому что для неё
синхронизация не нужна Почему так да
потому что объект Guard будет уничтожен
только вот здесь когда он выплатит за
область видимости функции Print и у него
будет вызван деструктор что мы можем
сделать вот в данный момент Ну во-первых
давайте действительно проверим что у нас
получится по скорости выполнения Итак
помните Когда я делал только с помощью
Log вот эту область кода с д дей по Т
восьмой кода у нас только что было 7
секунд если не верите можете назад
открутить а сейчас мы запустим с
Гарм получается 11 Секунд в чём проблема
Ну проблема в том что хотя вот эту вот
часть кода мы и можем выполнять
асинхронно то есть одновременно Но вот э
вот часть кода которое мы могли бы
выполнять в разных потоках одновременно
у нас всё равно синхронизируется потому
что ard объект ard её захватывает свой
контекст и уничтожается он только вот
здесь а значит укса вызывается уже после
вот этого момента что мы можем с этим
сделать мы можем просто ограничить
область видимости для нашего объекта р с
помощью скобочек
вот таким вот образом Обратите внимание
если мы за вот этими вот скобочка
попытаемся написать название объекта р
то нам Седа разработки будет ругаться
что она не видит такого объекта потому
что мы ограничили область видимости вот
этого вот всего кода вот этими скобочка
это в принципе ещё самые самые азы мы
где-то их изучали там ещё в начале
изучения C плюсов но тем не менее Вот
такую штуку здесь можно применить таким
образом раз область видимости объекта
гар и вот этого кода ограничена вот
этими вот скобочка то по сути объект гар
будет уничтожен вот здесь теперь А вот
эта часть кода сможет выполняться
асинхронно то есть одновременно в
нескольких потоках Таким образом мы
опять-таки должны получить скорость
выполнения около 7 секунд Давайте
забыться и проверим Ну так как будто бы
мы использовали обычный Лок без Лок
Гарда Ну вот Сем и одна То есть
практически тот же самый результат но
только мы не беспокоились об локе и
Unlock мтек просто указали ему область
вот этими вот скобочка где он должен
уничтожить то есть область его видимости
с помощью вот этих скобочек там где он
имеет право что-либо делать но если
точнее мы ему просто сказали что вот вот
здесь он уничтожит но здесь мы его
ручками создаём В общем вот такая вот
штука lard используется для тех же целей
что имтек только немножечко по-другому и
может обречь Вас от лишних ошибок вообще
идеальная вещь если у Вас должен быть
какой-то метод или какая-то функция
полностью синхронизированная вы просто
его создаёте этот гар в начале
исполнения метода или функции и
забываете про это всё то есть про Log
про Unlock Ну а если же вам в этом
методе или функции всё-таки нужно как-то
разграничивать синхронный асинхронный
код Ну тогда приходится использовать
какие-то вот такие штуки и на этом У
меня собственно Всё если вам понравился
этот урок он был для вас полезно
Weitere ähnliche Videos ansehen
FastAPI - Как использовать Depends #14
ИЗУЧИТЕ ГЛАВНУЮ НЕЙРОСЕТЬ МИРА от Б до Ю
#11. Спецсимволы, экранирование символов, raw-строки | Python для начинающих
ЭКОНОМИЯ ВРЕМЕНИ И ДЕНЕГ ПРИ ВЫБОРЕ НЕЙРОСЕТИ (МОДЕЛИ ТИПА LLM)
Join Strings Function | C Programming Example
James Devonport | Cloudflare Workers for Bubble Apps | Bubble.io
5.0 / 5 (0 votes)