Блок задач

12. Многопоточность

Сложность 5

Задача «Readers-writer lock»

Разработать синхронизационный объект (rwlock), позволяющий одновременное чтение данных несколькими потоками, но разрешающий запись данных только одному потоку.

Постановка задачи

Разработать набор классов:

  1. class rwlock; - основной класс, реализующий всю логику работы.
  2. class reader_lock - вспомогательный класс захватывающий объект на чтение. Должен использовать концепцию RAII для захвата и освобождения ресурса.
  3. class writer_lock - вспомогательный класс захватывающий объект на запись. Должен использовать концепцию RAII для захвата и освобождения ресурса.

Примерные интерфейсы классов (публичные методы).

Основной класс:

class rwlock {
public:
    rwlock();
    rwlock(const rwlock&) = delete;
    rwlock(rwlock&&);
    rwlock& operator=(const rwlock&) = delete;
    rwlock& operator=(rwlock&&);
    ~rwlock();

    bool read_lock(int64_t timeOut = -1); // попытка захвата объекта на чтение
    void read_unlock(); // освобождение объекта

    bool write_lock(int64_t timeOut = -1); // попытка захвата объекта на запись
    void write_unlock(); // освобождение объекта
}
  • rwlock() конструктор
  • rwlock(const rwlock&) = delete; - удалённый конструктор копирования
  • rwlock(rwlock&&); - move конструктор
  • rwlock& operator=(const rwlock&) = delete; - удалённый оператор =
  • rwlock& operator=(rwlock&&); - оператор =
  • ~rwlock();

  • bool read_lock(int64_t timeOut = -1); - попытка захвата объекта на чтение. Если объект не захвачен на запись, осуществляет захват на чтение. На чтение разрешается захватывать 'много' раз. Если объект захвачен на запись, осуществляет ожидание в течении timeOut (мс) и пытается захватить объект.

  • void read_unlock(); - освобождение ридера

  • bool write_lock(int64_t timeOut = -1); - попытка захвата объекта на запись. Если объект не захвачен на запись и не захвачен на чтение, осуществляет захват на запись. На запись разрешается захватывать только один раз. Если объект захвачен на запись или чтение, осуществляет ожидание в течении timeOut (мс) и пытается захватить объект.

  • void write_unlock(); // освобождение объекта

Вспомогательные классы:

class reader_lock {
public:
    reader_lock() = delete;
    reader_lock(const rwlock&) = delete;
    reader_lock(rwlock&&) = delete;
    reader_lock& operator=(const rwlock&) = delete;
    reader_lock& operator=(rwlock&&) = delete;

    reader_lock(rwlock& parent, bool auto = true, int64_t timeout = -1);
    ~reader_lock();
    bool is_locked();
    bool lock(int64_t timeout = -1);
    void unlock();
}
  • reader_lock() = delete;
  • reader_lock(const rwlock&) = delete;
  • reader_lock(rwlock&&) = delete;
  • reader_lock& operator=(const rwlock&) = delete;
  • reader_lock& operator=(rwlock&&) = delete;

  • reader_lock(rwlock& parent, bool auto = true, int64_t timeout = -1); - конструктор. Параметры: rwlock& parent - ссылка на основной объект, bool auto = true - захватывать автоматически, в конструкторе, int64_t timeout = -1 - время ожитания

  • ~reader_lock(); - деструктор. Если захвачен, освобождает основной объект (чтение)

  • bool is_locked(); - возвращает флаг - захвачен, не захвачен.

  • bool lock(int64_t timeout = -1); - попытка захвата объекта на чтение. Возврашает флаг успешности.

  • void unlock(); - освобождение чтения.

Замечание : lock/unlock - разрешается вызывать много раз, но кол-во вызовов unlock должно соответствовать кол-ву вызовов lock, включая начальный (в конструкторе).

class writer_lock {
public:
    writer_lock() = delete;
    writer_lock(const rwlock&) = delete;
    writer_lock(rwlock&&) = delete;
    writer_lock& operator=(const rwlock&) = delete;
    writer_lock& operator=(rwlock&&) = delete;

    writer_lock(rwlock& parent, bool auto = true, int64_t timeout = -1);
    ~writer_lock();
    bool is_locked();
    bool lock(int64_t timeout = -1);
    void unlock();
}
  • writer_lock() = delete;
  • writer_lock(const rwlock&) = delete;
  • writer_lock(rwlock&&) = delete;
  • writer_lock& operator=(const rwlock&) = delete;
  • writer_lock& operator=(rwlock&&) = delete;

  • writer_lock(rwlock& parent, bool auto = true, int64_t timeout = -1); - конструктор. Параметры: rwlock& parent - ссылка на основной объект, bool auto = true - захватывать автоматически, в конструкторе, int64_t timeout = -1 - время ожитания

  • ~writer_lock(); - деструктор. Если захвачен, освобождает основной объект (запись)

  • bool is_locked(); - возвращает флаг - захвачен, не захвачен.

  • bool lock(int64_t timeout = -1); - попытка захвата объекта на запись. Возврашает флаг успешности.

  • void unlock(); - освобождение записи.

Замечание : lock/unlock - разрешается вызывать много раз, но кол-во вызовов unlock должно соответствовать кол-ву вызовов lock, включая начальный (в конструкторе).