Блокировки чтения-записи Введение Получение и сброс блокировки чтения-записи Атрибуты блокировки чтения-записи Реализация Отмена выполнения потоков Пример.

Презентация:



Advertisements
Похожие презентации
POSIX Threads. Общая модель Программа Общая память Поток 1 CPU Поток 2 Поток N Потоки – наборы инструкций, исполняющиеся на CPU. Все потоки одной программы.
Advertisements

Атрибуты потоков Атрибуты являются способом определить поведение потока, отличное от поведения по умолчанию. При создании потока с помощью pthread_create()
Другие примитивы синхронизации Программирование с использованием POSIX thread library.
POSIX Threads & OpenMP Общая память Сергей Петрович Нечаев, Сибирский Суперкомпьютерный центр.
Работа с файлами Сазонов Д.О. ПМиЭММ Часть 2. Тема занятия: Работа с файлами через потоки Для реализации файлового ввода/вывода, необходимо включить в.
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
Система реального времени QNX/Neutrino (QNX6). QNX Микpоядеpная Cетевая Мyльтизадачная Многопользовательcкая.
Свойства потоков. Для досрочного завершения потока можно воспользоваться функцией pthread_cancel. Единственным аргументом этой функции является идентификатор.
Многопоточное программирование. Виды параллелизма. Общая память Распределенная память.
Кафедра ЮНЕСКО по НИТ1 Создание групп и коммуникаторов Параллельное программирование.
Практическое занятие 6. Функции. Большинство языков программирования используют понятия функции и процедуры. C++ формально не поддерживает понятие процедуры,
Основы ООП и C# Работа с объектами и классами. Классы Класс специальный тип данных для описания объектов. Он определяет данные и поведение типа. Определение.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Мутексы Программирование с использованием POSIX thread library.
Обработка исключительных ситуаций Исключительная ситуация (исключение) – это ошибка, возникающая во время выполнения программы. Например, ошибка работы.
Объектно-ориентированное программирование С++. Лекция 6 Карпов В.Э.
6. Средства синхронизации и взаимодействия процессов 6.1. Проблема синхронизации Процессам Процессам часто нужно взаимодействовать друг с другом, например,
Распределение памяти. Динамическое выделение памяти.
Лекция 8. Введение в ООП. Часть 1 Красс Александр СПбГУ ИТМО, 2008.
Физические модели баз данных Файловые структуры, используемые для хранения информации в базах данных.
Транксрипт:

Блокировки чтения-записи Введение Получение и сброс блокировки чтения-записи Атрибуты блокировки чтения-записи Реализация Отмена выполнения потоков Пример

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

Введение Правила действуют следующие: 1. Любое количество потоков могут заблокировать ресурс для считывания, если ни один процесс не заблокировал его на запись. 2. Блокировка чтения-записи может быть установлена на запись, только если ни один поток не заблокировал ресурс для чтения или для записи. Другими словами, произвольное количество потоков могут считывать данные, если ни один поток не изменяет их в данный момент. Данные могут быть изменены, только если никто другой их не считывает и не изменяет.

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

Введение Такой вид совместного доступа к ресурсу также носит название совместно-исключающей блокировки (shared-exclusive), поскольку тип используемой блокировки на чтение называется совместной блокировкой (shared lock), а тип используемой блокировки на запись называется исключающей блокировкой (exclusive lock).

Получение и сброс блокировки чтения-записи Блокировка чтения-записи имеет тип pthread_rwlock_t. Если переменная этого типа является статической, она может быть проинициализирована присваиванием значения константы PTHREAD_RWLOCK_INITIALIZER. Функция pthread_rwlock_rdlock позволяет заблокировать ресурс для чтения, причем вызвавший процесс будет заблокирован, если блокировка чтения- записи уже установлена записывающим процессом.

Получение и сброс блокировки чтения-записи Функция pthread_rwlock_wrlock позволяет заблокировать ресурс для записи, причем вызвавший процесс будет заблокирован, если блокировка чтения- записи уже установлена каким-либо другим процессом (считывающим или записывающим). Функция pthread_rwlock_unlock снимает блокировку любого типа (чтения или записи). Все функции возвращают 0 в случае успешного завершения, положительное значение Еххх - в случае ошибки.

Получение и сброс блокировки чтения-записи #include int pthread_rwlock_rdlock (pthread_rwlock_t *rwptr); int pthread_rwlock_wrlock (pthread_t rwlock_t *rwptr); int pthread_rwlock_unlock ( pthread_rwlock_t *rwptr);

Получение и сброс блокировки чтения-записи Следующие две функции производят попытку заблокировать ресурс для чтения или записи, но если это невозможно, возвращают ошибку с кодом EBUSY, вместо того чтобы приостановить выполнение вызвавшего процесса: #include int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwptr); int pthread_rwlock_trywrlock (pthread_rwlock_t *rwptr);

Атрибуты блокировки чтения-записи С татическая блокировка может быть проинициализирована присваиванием ей значения PTHREAD_RWLOCK_INITIALIZER. Эти переменные могут быть проинициализированы и динамически путем вызова функции pthread_rwlock_init. Когда поток перестает нуждаться в блокировке, он может вызвать pthread_rwlock_destroy :

Атрибуты блокировки чтения-записи #include int pthread_rwlock_init (pthread_rwlock_t *rwptr, const pthread_rw1ockattr_t *attr); int pthread_rwlock_destroy (pthread_rwlock_t *rwptr); Обе функции возвращают 0 в случае успешного завершения положительное значение Еххх - в случае ошибки.

Атрибуты блокировки чтения-записи Если при инициализации блокировки чтения- записи attr представляет собой нулевой указатель, атрибутам присваиваются значения по умолчанию. Для присваивания атрибутам других значений следует воспользоваться двумя функциями: #include int pthread_rwlockattr_init (pthread_rwlockattr_t *attr); int pthread_rwlockattr_destroy (pthread_rw1ockattr_t *attr);

Атрибуты блокировки чтения-записи После инициализации объекта типа pthread_rw1ockattr_t для установки или сброса отдельных атрибутов используются специальные функции. Единственный определенный на настоящее время атрибут PTHREAD_PROCESS_SHARED, который указывает на то, что блокировка используется несколькими процессами, а не отдельными потоками одного процесса. Две приведенные ниже функции используются для получения и установки значения этого атрибута:

Атрибуты блокировки чтения-записи #include int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *valptr); int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int value); Первая функция возвращает текущее значение в целом, на которое указывает аргумент valptr. Вторая функция устанавливает значение этого атрибута равным value, которое может быть либо PTHREAD_PROCESS_PRIVATE, либо PTHREAD_PROCESS_SHARED.

Реализация В листинге 1 приведен текст заголовочного файла pthread_rwlock.h, в котором определен основной тип pthread_rwlock_t и прототипы функций, работающих с блокировками чтения и записи Обычно все это находится в заголовочном файле листинге

Реализация 3-13 Наш тип pthread_rwlock_t содержит одно взаимное исключение, две условные переменные, один флаг и три счетчика. При просмотре или изменении содержимого этой структуры мы должны устанавливать блокировку rw_mutex. После успешной инициализации структуры полю rw_magic присваивается значение RW_MAGIC. Значение этого поля проверяется всеми функциями таким образом гарантируется, что вызвавший поток передал указатель на проинициализированную блокировку. Оно устанавливается в 0 после уничтожения блокировки.

Реализация Обратите внимание, что в счетчике rw_refcount всегда хранится текущий статус блокировки чтения-записи: -1 обозначает блокировку записи (и только одна такая блокировка может существовать в любой момент времени), 0 обозначает, что блокировка доступна и может быть установлена, а любое положительное значение соответствует количеству установленных блокировок на чтение Мы также определяем константу для статической инициализации нашей структуры.

Реализация Первая функция, pthread_rwlock_init, динамически инициализирует блокировку чтения-записи. Ее текст приведен в листинге 2.листинге 7-8 Присваивание атрибутов с помощью этой функции не поддерживается, поэтому мы проверяем, чтобы указатель attr был нулевым Мы инициализируем взаимное исключение и две условные переменные, которые содержатся в нашей структуре. Все три счетчика устанавливаются в 0, а полю rw_magiс присваивается значение, указывающее на то, что структура была проинициализирована.

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

Реализация Функция pthread_rwlock_rdlock выполняет получение блокировки на чтение. pthread_rwlock_rdlock 9-10 При работе со структурой pthread_rwlock_t всегда устанавливается блокировка на rw_mutex, являющееся ее полем Нельзя получить блокировку на чтение, если rw_refcount имеет отрицательное значение (блокировка установлена на запись) или имеются потоки, ожидающие получения блокировки на запись ( rw_nwaitwriters больше 0).

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

Реализация В листинге 5 показана функция pthread_rwlock_tryrdlock, которая не вызывает приостановления вызвавшего ее потока.листинге Если блокировка в данный момент установлена на запись или есть процессы, ожидающие возможности установить ее на запись, возвращается ошибка с кодом EBUSY. В противном случае мы устанавливаем блокировку, увеличивая значение счетчика rw_refcount.

Реализация Текст функции pthread_rwlock_wrlock приведен в листинге 6.листинге Если ресурс заблокирован на считывание или запись (значение rw_refcount отлично от 0), мы приостанавливаем выполнение потока. Для этого мы увеличиваем rw_nwaitwriters и вызываем pthread_cond_wait с условной переменной rw_condwriters. Для этой переменной посылается сигнал при снятии блокировки чтения-записи, если имеются ожидающие разрешения на запись процессы После получения блокировки на запись устанавливаем значение rw_refcount в -1.

Реализация Неблокирующая функция pthread_rwlock_trywrlock показана в листинге 7. листинге Если значение счетчика rw_refcount отлично от нуля, блокировка в данный момент уже установлена считывающим или записывающим процессом (это безразлично) и мы возвращаем ошибку с кодом EBUSY. В противном случае мы устанавливаем блокировку на запись, присвоив переменной rw_refcount значение -1.

Реализация Последняя функция, pthread_rwlock_unlock, приведена в листинге 8.листинге 16 Если rw_refcount больше 0, считывающий поток снимает блокировку на чтение. Если rw_refcount равно -1, записывающий поток снимает блокировку на запись. 22 Если имеются ожидающие разрешения на запись потоки, по условной переменной rw_condwnters передается сигнал (если блокировка свободна, то есть значение счетчика rw_refcount равно 0).

Реализация Мы знаем, что только один поток может осуществлять запись, поэтому используем функцию pthread_cond_signal. Если нет потоков, ожидающих возможности записи, но есть потоки, ожидающие возможности чтения, мы вызываем pthread_cond_broadcast для переменной rw_condreaders, поскольку возможно одновременное считывание несколькими потоками.

Отмена выполнения потоков Отмена выполнения может быть использована в том случае, если несколько потоков начинают работу над какой-то задачей (например, поиск записи в базе данных) и один из них завершает работу раньше всех остальных. Тогда он может отменить их выполнение. Другим примером является обнаружение ошибки одним из одновременно выполняющих задачу потоков, который затем может отменить выполнение и всех остальных. Для обработки отмены выполнения поток может установить (push) или снять (pop) обработчик- очиститель (cleanup handler):

Отмена выполнения потоков #include void pthread_cleanup_push(void (*function)(void *), void *arg); void pthread_cleanup_pop(int execute); Эти обработчики вызываются: в случае отмены выполнения потока (другим потоком, вызвавшим pthread_cancel); в случае добровольного завершения работы (вызовом pthread_exit или выходом из начальной функции потока).

Отмена выполнения потоков Обработчики-очистители выполняют всю необходимую работу по восстановлению значений переменных, такую как разблокирование взаимных исключений и семафоров, которые могли быть заблокированы данным потоком. Аргумент function представляет собой адрес вызываемой функции, a arg ее единственный аргумент. Функция pthread_cleanup_pop всегда удаляет обработчик из верхушки стека и вызывает эту функцию, если значение execute отлично от 0.

Пример

На рисунке изображена временная диаграмма выполнения нашей программы, а текст самой программы приведен в листинге 9.листинге 3 Создаются два потока, первый из которых выполняет функцию threadl, а второй thread2. После создания первого делается пауза длительностью в одну секунду, чтобы он успел заблокировать ресурс на чтение Мы ожидаем завершения работы второго потока и проверяем, что его статус. Затем мы ждем завершения работы первого потока и проверяем его статус. Затем мы уничтожаем блокировку.

Пример Поток 1 получает блокировку на чтение и ждет 3 секунды. Эта пауза дает возможность другому потоку вызвать pthread_rwlock_wrlock и заблокироваться при вызове pthread_cond_wait, поскольку блокировка на запись не может быть установлена из-за наличия блокировки на чтение. Затем первый поток вызывает pthread_cancel для отмены выполнения второго потока, ждет 3 секунды, освобождает блокировку на чтение и завершает работу.

Пример Второй поток делает попытку получить блокировку на запись (которую он может получить, когда первый поток снимет блокировку на чтение). Однако первый поток послал сигнал на отмену второго, что и произойдет после его разблокирования. Если первый поток не снимет блокировку (test 1), то второй не будет завершен и программа зависнет.

Пример В последнем листинге приведен пример использования блокировки, не приостанавливающих выполенеие вызвавшего их потока. Если глобальные переменные заблокированы, сделавший это поток отменяется. При этом происходит сброс блокировок.листинге