Поток — это наименьшая часть выполнения программы. Это легкие части процесса, использующие ту же память, что и основной процесс, поэтому взаимодействие между потоками упрощается. Каждый поток имеет свой собственный стек, набор регистров и счетчик программ, при этом разделяя сегмент кода и данных основного процесса.
Потоки в основном используются в программе для одновременного выполнения нескольких задач или наборов команд и для достижения максимального параллелизма. Однако одновременное использование потоков создает несколько проблем, таких как необходимость синхронизации.
Настоящая многозадачность достигается, когда настоящий параллелизм создается с помощью многоядерного процессора.
Разница между параллелизмом и параллелизмом.
Параллелизм — это состояние/возможность, при которой несколько задач выполняются одновременно либо на нескольких ядрах, либо на одном ядре посредством переключения контекста.
Принимая во внимание, что параллелизм — это выполнение нескольких задач одновременно на нескольких ядрах без упреждения и переключения контекста.
В параллельном режиме время начала и окончания потока может быть разным, но при параллельном выполнении потоки начинаются в одно и то же время, выполняются в одно и то же время и заканчиваются в одно и то же время.
Программные потоки и аппаратные потоки
Программные потоки — это те, которые создаются приложением во время самого выполнения и являются легкими по своей природе, и ОС рассматривает их как один процесс с одним выполняющимся потоком. Параллелизм в этом сценарии зависит от того, доступны ли несколько ядер или нет, если только потоки не будут выполняться одновременно.
Аппаратные потоки — это те, которые создаются самой ОС в ядре. Здесь вы найдете настоящий параллелизм и эффективное использование нескольких ядер. Кроме того, блокировка в одном потоке не блокирует другие потоки.
Что такое библиотеки потоков?
Библиотека потоков предлагает набор функций, классов и инструментов, которые абстрагируют основные сложности работы с потоками, упрощая разработчикам реализацию многопоточных функций.
Он включает в себя такие функции, как блокировка, мьютексы, условия, сигнализация и различные другие функции.
Жизненный цикл потока?
В своем жизненном цикле потоки проходят разные состояния:
- Новое: исходное состояние после создания потока.
- Работоспособен: поток готов к запуску, но ожидает, пока планировщик выделит время процессора.
- Заблокировано: поток временно неактивен, часто из-за ожидания какого-либо ресурса или условия.
- Завершено: поток завершил свое выполнение.
Многопоточность
Многопоточность — это процесс, в котором различные части выполнения программы передаются нескольким потокам для достижения параллелизма. Каждый поток имеет свой собственный стек, набор локальных переменных и счетчик программ, а также разделяет пространство памяти со своим соответствующим процессом. Это важно, поскольку задачи ввода-вывода могут выполняться отдельными потоками и, таким образом, инструкции могут выполняться параллельно без ожидания.
Создать поток очень просто: просто создайте переменную с типом потока, используя библиотеку потоков, а затем либо передайте функцию, либо создайте лямбда-функцию.
Основная проблема заключается в том, что как только программа прочитает поток t1, а затем выйдет за пределы основной области видимости, поток тоже перестанет выполняться, поскольку сам поток был частью основной функции.
Чтобы справиться с этой ситуацией, у нас есть две команды:
- . join() — после создания потока и задания ему задачи обязательно напишите t1.join(), прежде чем область действия закончится. Это гарантирует, что поток t1 завершит свое выполнение и будет работать правильно, прежде чем основная программа выйдет из области видимости. Мы можем создать несколько потоков и непосредственно перед завершением области действия вызвать функцию .join() для каждого из них. Это позволяет всем потокам выполняться один за другим синхронно.
- . detach( ) — вызов функции отсоединения через созданные вами потоки отсоединит их от основной программы, т. е. они начнут выполняться параллельно с основной функцией, и пока родительский процесс не будет завершен, он продолжит выполнение. Форекс — пользовательский интерфейс приложения.
Атомное ключевое слово
Теперь давайте возьмем пример переменной-счета внутри функции и предположим, что эта функция передается в двух потоках t1 и t2. Итак, t1 и t2 оба увеличивают счетчик, так что же происходит, когда t1 просто читает последнее значение счетчика и завершается в этом экземпляре, запланированный t2, и он тоже считывает значение счетчика, а также обновляет его. Итак, на данный момент t2 читает значение счетчика так же, как и значение t1, но t2 обновил его, и, поскольку t1 в конечном итоге запланирован снова, t1 в своем контексте сохранил предыдущее значение счетчика перед вытеснением и не знает, что t2 также обновил его. Так что в данном случае наблюдается несоответствие.
Чтобы этого не произошло, мы можем объявить count как атомарную переменную, и это позволит всем шагам обновления count читаться как один, т. е. просмотр текущего значения счетчика и его обновление будут считаться одним шагом, и, таким образом, достигается несогласованность. .
P.S. Ключевое слово Atomic используется только с переменными. Если CS состоит из нескольких шагов, то для достижения взаимного исключения необходимо использовать блокировки.
Что такое замки?
Блокировка — это механизм синхронизации, используемый для ограничения критической секции одним потоком за раз и предотвращения состояний гонки.
Существуют различные замки:
- Блокировка мьютекса — базовая блокировка, которая обеспечивает взаимное исключение, и только одна блокировка может одновременно удерживать мьютекс.
- Семафоры: блокировка, которая позволяет определенному количеству потоков одновременно входить в CS, обеспечивая контроль над параллелизмом.
- Реентерабельная блокировка: блокировка, которая позволяет потоку повторно войти в CS в то время, когда он удерживает CS.
- Блокировка чтения-записи: эта блокировка позволяет нескольким потокам читать CS, позволяя только одному потоку записывать CS.
Что такое мьютекс?
Мьютекс, обозначающий взаимное исключение, — это механизм синхронизации, который позволяет только одному потоку входить в CS и запрещает нескольким потокам одновременно входить в CS.
Мьютекс используется с блокировкой, и поток, получивший блокировку, может безопасно получить доступ к CS, и при этом ни один другой поток не может получить доступ к CS, также это дает возможность включить повторную блокировку, но только на определенное время, так что никакие другие потоки не ждут CS бесконечно.
Два разных типа мьютексных блокировок.
- Защита блокировки. Защита блокировки — это блокировка на основе области действия, которая блокирует CS, как только блокировка создается с использованием мьютекса, и в тот момент, когда область пересекается, блокировка снимается, даже если CS выдает какое-либо исключение. Это помогает управлять утечками ресурсов, поскольку нам не придется разблокировать замок.
- Уникальная блокировка. В этой блокировке вы можете включить блокировку, и она разблокируется, как только мы выйдем за пределы области действия, но наряду с этим можно также выполнить разблокировку вручную.
Кроме того, уникальная блокировка предоставляет функцию отложенной блокировки, которая позволяет нам инициализировать уникальную блокировку без удержания мьютекса, а затем мы можем инициировать эту блокировку в любой момент, когда захотим.
Наряду с этой уникальной блокировкой также имеется функция условия, которая ограничивает дальнейшее выполнение потока до тех пор, пока не будет достигнуто это конкретное условие.
Планирование потоков
Потоки могут быть вытеснены, а другие потоки могут быть запланированы в зависимости от приоритетов потоков и типа планирования, которому следует конкретная ОС. Другим алгоритмом планирования может быть FCFS и циклический алгоритм, который также имеет временной квант.
Обещание и будущее
Promise и Future — это примитивы синхронизации, используемые для безопасного установления связи между двумя потоками. Они в основном используются, когда нам нужно передать данные из потока в другой.
Обещать
Обещание — это объект синхронизации, представляющий значение или результат, который будет доступен в будущем. По сути, он устанавливает результат, который будет доставлен после завершения выполнения потока. Это устраняет необходимость ожидания занятости и ресурсы ЦП не тратятся впустую.
Будущее
Будущее — это то же самое, что и обещание, и представляет собой ценность, которая будет доступна в будущем. Однако будущее используется для получения или извлечения этого значения в потребительском потоке.
Таким образом, если значение недоступно в конкретном экземпляре, поток не зацикливается, а блокируется до тех пор, пока значение не будет получено.
Исключения
Помимо установки и получения результата, исключения также являются частью взаимодействия между потоками. Исключение — это ненормальная или непредвиденная ситуация, возникающая во время выполнения программы, вызывающая нарушение нормального выполнения программы.
Исключения обычно создаются из-за различных крайних случаев, таких как деление на ноль или файл не найден. Итак, чтобы программа не вылетела и мы знали, в чем проблема, мы «выбрасываем» исключение в этих крайних случаях, а затем перехватываем его в будущем.
Промис вступает в игру, поскольку он устанавливает исключение, и если результат не может быть доставлен, то промис доставляет это исключение, и в будущем вместо получения результата появляется ошибка, которую он отображает.