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

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

Настоящая многозадачность достигается, когда настоящий параллелизм создается с помощью многоядерного процессора.

Разница между параллелизмом и параллелизмом.

Параллелизм — это состояние/возможность, при которой несколько задач выполняются одновременно либо на нескольких ядрах, либо на одном ядре посредством переключения контекста.

Принимая во внимание, что параллелизм — это выполнение нескольких задач одновременно на нескольких ядрах без упреждения и переключения контекста.

В параллельном режиме время начала и окончания потока может быть разным, но при параллельном выполнении потоки начинаются в одно и то же время, выполняются в одно и то же время и заканчиваются в одно и то же время.

Программные потоки и аппаратные потоки

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

Аппаратные потоки — это те, которые создаются самой ОС в ядре. Здесь вы найдете настоящий параллелизм и эффективное использование нескольких ядер. Кроме того, блокировка в одном потоке не блокирует другие потоки.

Что такое библиотеки потоков?

Библиотека потоков предлагает набор функций, классов и инструментов, которые абстрагируют основные сложности работы с потоками, упрощая разработчикам реализацию многопоточных функций.

Он включает в себя такие функции, как блокировка, мьютексы, условия, сигнализация и различные другие функции.

Жизненный цикл потока?

В своем жизненном цикле потоки проходят разные состояния:

  • Новое: исходное состояние после создания потока.
  • Работоспособен: поток готов к запуску, но ожидает, пока планировщик выделит время процессора.
  • Заблокировано: поток временно неактивен, часто из-за ожидания какого-либо ресурса или условия.
  • Завершено: поток завершил свое выполнение.

Многопоточность

Многопоточность — это процесс, в котором различные части выполнения программы передаются нескольким потокам для достижения параллелизма. Каждый поток имеет свой собственный стек, набор локальных переменных и счетчик программ, а также разделяет пространство памяти со своим соответствующим процессом. Это важно, поскольку задачи ввода-вывода могут выполняться отдельными потоками и, таким образом, инструкции могут выполняться параллельно без ожидания.

Создать поток очень просто: просто создайте переменную с типом потока, используя библиотеку потоков, а затем либо передайте функцию, либо создайте лямбда-функцию.

Основная проблема заключается в том, что как только программа прочитает поток 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 — это примитивы синхронизации, используемые для безопасного установления связи между двумя потоками. Они в основном используются, когда нам нужно передать данные из потока в другой.

Обещать

Обещание — это объект синхронизации, представляющий значение или результат, который будет доступен в будущем. По сути, он устанавливает результат, который будет доставлен после завершения выполнения потока. Это устраняет необходимость ожидания занятости и ресурсы ЦП не тратятся впустую.

Будущее

Будущее — это то же самое, что и обещание, и представляет собой ценность, которая будет доступна в будущем. Однако будущее используется для получения или извлечения этого значения в потребительском потоке.

Таким образом, если значение недоступно в конкретном экземпляре, поток не зацикливается, а блокируется до тех пор, пока значение не будет получено.

Исключения

Помимо установки и получения результата, исключения также являются частью взаимодействия между потоками. Исключение — это ненормальная или непредвиденная ситуация, возникающая во время выполнения программы, вызывающая нарушение нормального выполнения программы.

Исключения обычно создаются из-за различных крайних случаев, таких как деление на ноль или файл не найден. Итак, чтобы программа не вылетела и мы знали, в чем проблема, мы «выбрасываем» исключение в этих крайних случаях, а затем перехватываем его в будущем.

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