|
Программирование >> Формирование пользовательского контейнера
Обсуждение проблемы синхронизации Операционная система Windows должна обеспечивать специальные сервисы, которые позволяют синхронизировать доступ к разделяемому ресурсу, так как без помощи операционной системы процесс или поток не узнает о том, что у него есть исключительное право (sole) доступа к ресурсу. Для того чтобы лучше понять это, представьте, что вы пишете программы для многозадачной операционной системы, которая не обеспечивает никой поддержки синхронизации. Представим далее, что у вас есть два одновременно выполняющихся потока А и В, каждому из которых время от времени нужен доступ к некоторому ресурсу R (например, к файлу на диске), способному предоставить доступ только одному потоку в каждый определенный момент времени. Для того чтобы помешать доступу к R одного потока, в то время, когда другой поток использует этот ресурс, вы пробуете реализовать следующее решение. Во-первых, вы создаете переменную, названную flag, которая инициализируется с нулевым значением и доступна обоим потокам. Далее перед использованием фрагмента кода, в котором выполняется доступ к R, вы ждете очистки переменной flag, затем устанавливаете эту переменную, обращаетесь к ресурсу R и в конце очи- Синхронизация При наличии фуппы потоков или процессов иногда необходимо координировать действия двух или нескольких. Этот процесс называют синхронизацией (synchronization). Наиболее общий пример необходимости синхронизации - организация доступа двух или нескольких потоков к разделяемому ресурсу, который должен использоваться одним потоком в каждый определенный момент времени. Например, если один поток записывает информацию в файл, другому потоку надо помешать делать в это время то же самое. Не обойтись без синхронизации и в том случае, когда один поток ждет события, которое вызывается другим потоком. В такой ситуации нужны некоторые средства, благодаря которым первый поток удерживается в состоянии ожидания до тех пор, пока не произойдет нужное событие. После этого отложенный поток должен продолжить выполнение. Задача может находиться в двух основных состояниях. Во-первых, она может выполняться (или быть готовой выполниться, как только получит порцию времени). Во-вторых, задача может быть блокирована в ожидании некоторого ресурса или события, в этом случае ее выполнение приостанавливается до тех пор, пока требуемый ресурс не станет доступным или ожидаемое событие не произойдет. Если вы не знакомы с проблемой синхронизации и наиболее общим ее решением, семафором, следующий подраздел поможет вам. щаете flag. Таким образом, перед доступом любого потока к ресурсу R он выполнит следующий фрагмент кода: xle(flag) ; ожидает очистки flag flag =1 устанавливает flag доступ к ресурсу R flag =0; очищает flag Идея, реализованная в этом коде, заключается в том, что ни один поток не получит доступа к ресурсу R, если переменная flag установлена, т. е. содержит ненулевое значение. Теоретически такой подход ведет к правильному решению, но в действительности он оставляет желать лучшего, потому что не всегда будет работать. Давайте рассмотрим почему. Приведенный код на самом деле не препятствует одновременному доступу обоих потоков к ресурсу R. Цикл while по существу выполняет повторяющиеся операторы зафузки и сравнения для переменной flag. Другими словами, он тестирует значение этой переменной. Когда она очищена, следующая строка кода присваивает 1 переменной flag. К несчастью, эти две операции могут выполниться в двух разных квантах времени, между которыми доступ к переменной flag может получить другой поток и, таким образом, тоже обзавестись разрешением на доступ к ресурсу R в то же самое время. Чтобы лучше понять, представьте, что поток А входит в цикл while и обнаруживает, что переменная flag равна нулю, т. е. дан зеленый свет для доступа к R. Однако прежде чем он успел установить значение flag равным 1, его квант времени закончился, и поток В возобновил выполнение. Если В выполнит свой цикл while, то также обнаружит, что переменная flag равна нулю, и предположит, что безопасно обращаться к ресурсу R. Когда же поток А возобновится, он тоже обратится к R. Решающая причина возникшей проблемы состоит в том, что проверка и установка переменной flag не включены в состав одной неразрывной операции. Более того, как только что было показано, они могут быть выполнены в разных квантах процессорного времени. Как бы вы не старались, эту проблему нельзя решить на уровне кода приложения так, чтобы получить абсолютную гарантию того, что один и только один поток имеет доступ к ресурсу в определенный момент времени. Решение проблемы синхронизации столь же элегантно, сколь и просто. Операционная система (в данном случае Windows) предоставляет процедуру, представляющую собой одну неразрывную операцию, которая тестирует, 3 при необходимости и устанавливает значение переменной flag. На языке системных инженеров она называется операцией проверки и установки. Исторически сложилось так, что флаги, используемые для управления доступом разделяемому ресурсу и обеспечения синхронизации потоков (или процес-*ов), называются семафорами. Семафор - сердцевина системы синхрониза-ии операционной системы Windows. Объекты синхронизации в Windows Операционная система Windows поддерживает различные типы объектов синхронизации. Первый тип - классический семафор. При использовании семафора доступ к ресурсу можно полностью синхронизировать, т. е. один и только один поток или процесс сможет обращаться к ресурсу в каждый конкретный момент времени, или семафор может позволить лишь небольшому числу процессов или потоков получать доступ в любой момент времени. Семафоры реализованы с помощью счетчика, текущее значение которого увеличивается, когда семафор предоставляется программе, и уменьшается, когда он освобождается. Второй тип объекта синхронизации - мьютекс-семафор или просто мью-текс (mutex) для краткости. Мьютекс синхронизирует доступ к ресурсу таким образом, что один и только один поток или процесс может обращаться к ресурсу в каждый момент времени. По существу, мьютекс - это специальная версия стандартного семафора. Третий тип объекта синхронизации - объект-событие. Его можно применять для блокировки доступа к ресурсу до тех пор, пока какой-нибудь другой поток или процесс не сообщит, что ресурс можно использовать (т. е. объект-событие сигнализирует о том, что заданное событие произошло). Четвертый тип объекта синхронизации - таймер ожидания. Такой таймер блокирует выполнение потока до определенного времени. Можно также создать очереди таймеров, которые представляют собой списки таймеров ожидания. Вы можете запретить использовать часть кода более чем одному потоку в каждый конкретный момент времени, превратив ее в критическую секцию с помошью объекта-критической секции. Как только в критическую секцию вошел один поток, никакой другой поток не может ее использовать до тех пор, пока первый поток не покинет критическую секцию. В этой главе будет применен только один тип объекта синхронизации - мьютекс, описание которого дано в следующем разделе. Но профаммисту на С++ доступны все объекты синхронизации, предоставляемые операционной системой Windows. Как уже отмечалось, одно из главных преимуществ, обусловленное тем, что язык С++ полагается на поддержку многопоточности операционной системой, - все средства многопоточности у вас под началом. Использование мьютекса для синхронизации потоков Как уже отмечалось, мьютекс - это специальный семафор, который разрешает только одному потоку доступ к ресурсу в любой конкретный момент
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |