Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
vovk.doc
Скачиваний:
2
Добавлен:
01.04.2025
Размер:
456 Кб
Скачать
☆

25. Синхронізація операцій читання-запису.

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

При работе потоков возникает необходимость разделения некоторых структурных данных. Ясно, что в любой момент времени только 1 поток может записывать в структуру, поэтому поток «писатель» должен получить эксклюзивную блокировку чтения/записи – rwlock. При этом право доступа к ресурсу контролируется на добровольных началах, т.е. за синхронизацию потоков «писателей» и потоков «читателей» отвечает программист.

Для блокировок чт/зап используются вызовы:

  1. инициализация внутренних областей памяти для rwlock блокировок

int pthread_rwlock_init(pthread_rwlock_t *lock, const pthread_rwlockattr_t *attr);

Эта функция принимает аргумент lock и инициализирует его атрибутами, указанными в attr.

  1. Уничтожение блокировок

int pthread_rwlock_destroy(pthread_rwlock_t *lock);

  1. Установка атрибутов

int pthread_rwlockattr_init();

int –“– _destroy();

int –“– _getpshared();

int –“– _setpshared();

Нельзя использовать блокировку, которая еще не инициализирована или уже уничтожена.

  1. Выбор типа блокировки: «читателям» - не эксклюзивный доступ, «писателю» - эксклюзивный. По «читателям» и «писателям» блокировки разные.

int pthread_rwlock_rdlock(pthread_rwlock_t *lock); - блокировка потока, если ресурс недоступен.

int pthread_rwlock_tryrdlock(pthread_rwlock_t *lock); - не блокирующий вызов для «читателя», при неудаче – возвращается код ошибки.

int pthread_rwlock_wrlock(pthread_rwlock_t *lock); - блокирующий вызов для «писателя».

int pthread_rwlock_trywrlock(pthread_rwlock_t *lock); - не блокирующий вызов.

Как и блокирующий так и не блокирующий вызов получает блокировку, если она доступна, но если блокировка недоступна, то при блокирующем вызове поток будет блокированным, а при не блокирующем вызове – нет.

  1. Освобождение блокировки

int pthread_rwlock_unlock(pthread_rwlock_t *lock);

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

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

26.Синхронізація потоків за ”чекаючим блокуванням”.

Иногда при выполнении синхронизации нам нужно чтобы поток ожидал некоторого события. Например, когда доступны данные от устройства, или когда данные сохранены на диск и т.д. Ещё одна особенность данной ситуации состоит в том, что одного и того же события могут ожидать несколько потоков. Для таких целей можно использовать либо условную переменную либо ждущую блокировку.

Для выполнения метода „ждущих блокировками” необходимо выполнить некоторые опреации:

-захват внутреннего мютекса(mutex) библиотек ждущих блокировок

int pthread_sleepon_lock(void);

-освобождение мютекса

int pthread_sleepon_unlock(void);

-ожидания события по указанному адресу

int pthread_sleepon_wait(void*addr);

-отправки сигнала одному из потоков

int pthread_sleepon_signal(void*addr);

-отправки сигнала нескольким потокам

int pthread_sleepon_broadcast(void*addr);

Отметим, что несмотря на префикс «pthread_», вышеперечисленные функции не предусмотрены стандартами POSIX.

Для наглядного примера можна написать такую программу, где один поток является поставщиком данных, а другой потребителем:

Для удобства написания такой программы нам нужно ввести переменную flag, которая будет принимать значения 0 если данных нет, или 1 если данные есть.

#include<stdio.h>

#include<pthread.h>

#include<unistd.h>

volatile int flag=0;

void * consumer (void * not_used)

{printf(“This is consumer\n”); \\потребитель

while(1)

{ pthread_sleepon_lock(); //захват внутреннего мютекса

while(!flag) pthread_sleepon_wait(&flag);

sleep(1); //имитация обработки данных

flag=0; //данных нет

pthread_sleepon_unlock();}}

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

Рассмотрим функцию производителя: void * producer(void * not_used){

while(1){ sleep(2); // имитация получения данных

pthread_sleepon_lock();

flag=1; // данные теперь есть

pthread_sleepon_signal(&flag); //посылаем сигнал потоку

pthread_sleepon_unlock();

}}

int main()

{ printf(‘Example\n’);

pthread_create(NULL,NULL,producer,NUUL);

pthread_create(NULL,NULL,consumer,NUUL);

sleep(30);}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]