Введение

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

Реализация критических разделов

Реализация критических секций различается в разных операционных системах. Критическая секция обычно завершается за конечное время, и поток, задача или процесс должны ожидать фиксированное время, чтобы войти в неё (ограниченное ожидание). Для обеспечения исключительного использования критических секций требуется некоторый механизм синхронизации при входе и выходе из программы. Критическая секция – это фрагмент программы, требующий взаимоисключающего доступа. Как показано на рисунке, в случае взаимоисключения (мьютекса) один поток блокирует критическую секцию, используя механизмы блокировки, когда ему необходимо получить доступ к общему ресурсу, а другие потоки должны ждать своей очереди для входа в секцию. Это предотвращает конфликты, когда два или более потоков совместно используют одно и то же адресное пространство и хотят получить доступ к общему ресурсу. После выхода из критической секции, и в некоторых случаях после завершения квант времени, будет выполнен ожидающее прерывание. Концепция кванта времени применима к планированию методом "round robin" и аналогичным политикам планирования. Поскольку критические секции могут выполняться только на процессоре, на котором они были вызваны, синхронизация требуется только в пределах этого процессора. Это позволяет входить и выходить из критических секций практически без затрат. Межпроцессорная синхронизация не требуется. Необходима только синхронизация потока инструкций. Большинство процессоров обеспечивают необходимый уровень синхронизации, прерывая текущее состояние выполнения. Это позволяет в большинстве случаев критическим секциям быть не более чем счётчиком вызовов критических секций для каждого процессора. Улучшения производительности включают выполнение ожидающих прерываний при выходе из всех критических секций и разрешение планировщику выполняться при выходе из всех критических секций. Кроме того, ожидающие прерывания могут быть переданы другим процессорам для выполнения. Критические секции не следует использовать в качестве длительного примитива блокировки. Критические секции должны быть достаточно короткими, чтобы их можно было войти, выполнить и выйти без каких-либо прерываний со стороны оборудования и планировщика. Критические секции ядра лежат в основе проблемы программной блокировки.

Критические разделы в структурах данных

При параллельном программировании код разделяется на потоки. Переменные, к которым осуществляется одновременное чтение и запись, распределяются между потоками, и каждый поток имеет свою копию этих переменных. Структуры данных, такие как связанные списки, деревья и хеш-таблицы, содержат связанные переменные данных, которые нельзя разделить между потоками, что значительно усложняет реализацию параллелизма. Для повышения эффективности реализации структур данных, такие операции, как вставка, удаление и поиск, могут выполняться параллельно. Однако в процессе выполнения этих операций могут возникать ситуации, когда один поток ищет элемент, а другой – удаляет его. В таких случаях результат может быть некорректным: поток, выполняющий поиск, может найти элемент, в то время как другой поток уже удалил его. Это приведет к ошибкам в работе программы и выдаче неверных данных. Чтобы избежать этого, одним из способов является защита всей структуры данных критической секцией, чтобы обеспечить последовательное выполнение операций. Другой способ – блокировка используемого узла в критической секции, чтобы другие операции не могли использовать тот же узел. Таким образом, использование критической секции гарантирует, что код выдает ожидаемые результаты.

Критические секции в отношении периферийных устройств

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