Блокировка чтения-записиБлокировка чтения-записи — механизм синхронизации, разрешающий одновременное общее чтение некоторых разделяемых данных либо их эксклюзивное изменение, разграничивая таким образом блокировки на чтение и на запись между собой[1]. Механизм призван решить классическую задачу о читателях-писателях, в которой некоторый объект одновременно читается и пишется конкурентными задачами[2]. В отличие от мьютексов блокировки чтения-записи отдельно учитывают чтение данных и отдельно — запись, разрешая обращение к данным, если они в это время не изменяются. Мьютексы же допускают только эксклюзивный доступ к данным[1]. Однако встречаются разделяемые мьютексы, предоставляющие помимо эксклюзивной блокировки общую, позволяющую совместно владеть мьютексом, если нет эксклюзивного владельца[3]. По своей сути разделяемые мьютексы являются блокировками чтения-записи, но именуются мьютексами. В общем случае блокировки чтения-записи решают ту же задачу, что и мьютексы, и могут быть ими заменены, причиной же появления механизма блокировок чтения-записи является повышение эффективности взаимного исключения при раздельном чтении и записи[4]. Блокировки чтения-записи являются более предпочтительными, чем мьютексы, в случаях, когда обращения к данным происходят намного чаще, чем их запись. В этом случае читающие задачи не будут блокироваться большую части времени, лишь иногда блокируясь при изменениях объекта. Приоритет между пишущими и читающими задачами часто отдаётся пишущим задачам, чтобы избежать ресурсного голодания пишущих задач[1]. Задача о читателях-писателяхПроблема читателей и писателей возникает в любой ситуации, когда требуется одновременное чтение и изменение структуры данных, файловой системы или базы данных конкурентными задачами. Чтение неизменных данных может осуществляться одновременно множеством задач, однако если в это время будет происходить изменение данных, параллельное их чтение может привести к получению частично изменённых данных, то есть испорченных[2]. Решение задачи является асимметричным и предполагает разделение блокировки на чтение и на запись. Изменение данных допускается лишь эксклюзивное, то есть только одна задача может единовременно захватывать блокировку на запись, если только не захвачена блокировка на чтение. Чтение данных может осуществляться многими задачами, поэтому блокировку на чтение могут захватить одновременно сколько угодно задач, если только не захвачена блокировка на запись. То есть критические секции записи и чтения не могут исполняться параллельно, но критические секции чтения — могут[2]. Алгоритмы реализацииСамым простым алгоритмом реализации на семафорах и мьютексах является использование выключателя бинарного семафора. Запись должна защищаться данным семафором. Первая читающая задача должна захватывать семафор с помощью выключателя, блокируя пишущие потоки, а последняя заканчивающая свою работы — должна отпускать семафор, разрешая пишущим задачам продолжить свою работу[5]. Однако данная реализация имеет одну серьёзную проблему, сравнимую с взаимной блокировкой, — ресурсное голодание пишущих задач[6]. Псевдокод простого алгоритма блокировок чтения-записи
Универсальный алгоритм, лишённый описанной выше проблемы, включает в себя выключатель бинарного семафора А для организации критической секции читающих задач и турникет для блокировки новых читающих задач при наличии ожидающих пишущих. При появлении первой читающей задачи она захватывает семафор А с помощью выключателя, запрещая запись. Для пишущих задач семафор А защищает критическую секцию записи, поэтому, если он захвачен читающими задачами, все пишущие задачи блокируются при входе в свою критическую секцию. Однако захват пишущими задачами семафора А с последующей записью защищается семафором турникета. Поэтому, если произошла блокировка пишущей задачи из-за наличия читающих, турникет блокируется вместе с новыми читающими задачами. Как только последняя читающая заканчивает свою работу, семафор выключателя отпускается, и первая в очереди пишущая задача разблокируется. По окончании своей работы она отпускает семафор турникета, снова разрешая работу читающих задач[7]. Псевдокод универсального алгоритма блокировок чтения-записи
На уровне операционных систем существуют реализации семафоров чтения и записи, которые специальным образом модифицируются для повышения эффективности при массовом использовании. Реализации блокировок чтения-записи могут быть основаны как на мьютексах, так и на спин-блокировках[4]. Проблемы использованияХотя блокировки чтения-записи позволяют повысить скорость работы некоторых алгоритмов, им присуща скрытая проблема, которая проявляется при равномерной плотности запросов на чтение данных. В этом случае захват блокировки на запись может откладываться на неограниченные промежутки времени, порождая ресурсное голодание пишущих задач[4]. Ресурсное голодание пишущих задач сравнимо с взаимной блокировкой, поскольку запись данных будет невозможной, пока прибывают новые читающие задачи. При этом проблема может оказаться незаметной, пока нагрузка на систему не очень высокая, но может начать проявляться при возрастании нагрузки. Решение может быть заложено в реализацию блокировок чтения-записи и предполагает блокировку любых новых читающих задач, если в ожидании блокировки есть хотя бы одна пишущая[6]. Повышение блокировки до пишущейКонцепция повышения уровня блокировки позволяет повысить захваченную блокировку на чтение до эксклюзивной блокировки на запись. Повышение блокировки происходит, когда больше не оказывается других читающих задач, в противном случае задача блокируется до тех пор, пока читающие задачи не отпустят блокировку. Концепция также допускает понижение блокировки записи до блокировки чтения[8]. Однако концепция зачастую является опциональной и не обязана присутствовать в конкретных реализациях. Прикладное программированиеПоддержка в POSIXВ стандарте POSIX блокировки чтения-записи представлены типом Поддержка в Win32 APIВ прикладном интерфейсе программирования Windows блокировки представлены структурой Поддержка в языках программирования
См. такжеПримечания
Литература
|
Portal di Ensiklopedia Dunia