Spec-Zone.ru › D

core.sync.rwmutex

Модуль читательско-записного мьютекса предоставляет примитив для поддержания совместного доступа для чтения и взаимоисключающего доступа для записи.

Лицензия:
Boost License 1.0
Авторы:
Шон Келли
Источник
core/sync/rwmutex.d
class ReadWriteMutex;

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

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

Примеры:
import core.atomic, core.thread, core.sync.semaphore;

static void runTest(ReadWriteMutex.Policy policy)
{
    scope mutex = new ReadWriteMutex(policy);
    scope rdSemA = new Semaphore, rdSemB = new Semaphore,
          wrSemA = new Semaphore, wrSemB = new Semaphore;
    shared size_t numReaders, numWriters;

    void readerFn()
    {
        synchronized (mutex.reader)
        {
            atomicOp!"+="(numReaders, 1);
            rdSemA.notify();
            rdSemB.wait();
            atomicOp!"-="(numReaders, 1);
        }
    }

    void writerFn()
    {
        synchronized (mutex.writer)
        {
            atomicOp!"+="(numWriters, 1);
            wrSemA.notify();
            wrSemB.wait();
            atomicOp!"-="(numWriters, 1);
        }
    }

    void waitQueued(size_t queuedReaders, size_t queuedWriters)
    {
        for (;;)
        {
            synchronized (mutex.m_commonMutex)
            {
                if (mutex.m_numQueuedReaders == queuedReaders &&
                    mutex.m_numQueuedWriters == queuedWriters)
                    break;
            }
            Thread.yield();
        }
    }

    scope group = new ThreadGroup;

    // 2 simultaneous readers
    group.create(&readerFn); group.create(&readerFn);
    rdSemA.wait(); rdSemA.wait();
    assert(numReaders == 2);
    rdSemB.notify(); rdSemB.notify();
    group.joinAll();
    assert(numReaders == 0);
    foreach (t; group) group.remove(t);

    // 1 writer at a time
    group.create(&writerFn); group.create(&writerFn);
    wrSemA.wait();
    assert(!wrSemA.tryWait());
    assert(numWriters == 1);
    wrSemB.notify();
    wrSemA.wait();
    assert(numWriters == 1);
    wrSemB.notify();
    group.joinAll();
    assert(numWriters == 0);
    foreach (t; group) group.remove(t);

    // reader and writer are mutually exclusive
    group.create(&readerFn);
    rdSemA.wait();
    group.create(&writerFn);
    waitQueued(0, 1);
    assert(!wrSemA.tryWait());
    assert(numReaders == 1 && numWriters == 0);
    rdSemB.notify();
    wrSemA.wait();
    assert(numReaders == 0 && numWriters == 1);
    wrSemB.notify();
    group.joinAll();
    assert(numReaders == 0 && numWriters == 0);
    foreach (t; group) group.remove(t);

    // writer and reader are mutually exclusive
    group.create(&writerFn);
    wrSemA.wait();
    group.create(&readerFn);
    waitQueued(1, 0);
    assert(!rdSemA.tryWait());
    assert(numReaders == 0 && numWriters == 1);
    wrSemB.notify();
    rdSemA.wait();
    assert(numReaders == 1 && numWriters == 0);
    rdSemB.notify();
    group.joinAll();
    assert(numReaders == 0 && numWriters == 0);
    foreach (t; group) group.remove(t);

    // policy determines whether queued reader or writers progress first
    group.create(&writerFn);
    wrSemA.wait();
    group.create(&readerFn);
    group.create(&writerFn);
    waitQueued(1, 1);
    assert(numReaders == 0 && numWriters == 1);
    wrSemB.notify();

    if (policy == ReadWriteMutex.Policy.PREFER_READERS)
    {
        rdSemA.wait();
        assert(numReaders == 1 && numWriters == 0);
        rdSemB.notify();
        wrSemA.wait();
        assert(numReaders == 0 && numWriters == 1);
        wrSemB.notify();
    }
    else if (policy == ReadWriteMutex.Policy.PREFER_WRITERS)
    {
        wrSemA.wait();
        assert(numReaders == 0 && numWriters == 1);
        wrSemB.notify();
        rdSemA.wait();
        assert(numReaders == 1 && numWriters == 0);
        rdSemB.notify();
    }
    group.joinAll();
    assert(numReaders == 0 && numWriters == 0);
    foreach (t; group) group.remove(t);
}
runTest(ReadWriteMutex.Policy.PREFER_READERS);
runTest(ReadWriteMutex.Policy.PREFER_WRITERS);
перечисление Policy: int;

Определяет политику, используемую этим мьютексом. В настоящее время определены две политики.

Первая поместит писателей в очередь, пока нет ни одного читателя, держащего мьютекс, затем пропустит писателей по одному. Если читатель получает мьютекс, в то время как в очереди все еще есть писатели, читатель получит приоритет.

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

Будущие политики могут предложить более сбалансированный подход между приоритетами читателей и писателей.

PREFER_READERS

Читатели имеют приоритет. Это может привести к голоданию писателей.

PREFER_WRITERS

Писатели имеют приоритет. Это может привести к голоданию читателей.

this(Policy policy = Policy.PREFER_WRITERS);

Инициализирует объект читательско-записного мьютекса с заданной политикой.

Параметры:
Policy policy Используемая политика.
Исключения:
SyncError при ошибке.
@property Policy policy();

Получает политику, используемую этим мьютексом.

Возвращает:
Используемая политика мьютекса.
@property Reader reader();

Получает объект, представляющий блокировку чтения для связанного мьютекса.

Возвращает:
Подмьютекс читателя.
@property Writer writer();

Получает объект, представляющий блокировку записи для связанного мьютекса.

Возвращает:
Подмьютекс писателя.
class Reader: object.Object.Monitor;

Этот класс может рассматриваться как мьютекс сам по себе и используется для переговоров о блокировке чтения для окружающего мьютекса.

this();

Инициализирует объект-прокси читателя читательско-записного мьютекса.

@trusted void lock();

Приобретает блокировку чтения для окружающего мьютекса.

@trusted void unlock();

Освобождает блокировку чтения для окружающего мьютекса.

bool tryLock();

Попытка получить блокировку чтения для окружающего мьютекса. Если блокировка может быть получена без ожидания, блокировка приобретается, и возвращается true. Если нет, блокировка не приобретается, и возвращается false.

Возвращает:
true, если блокировка была приобретена, и false, если нет.
bool tryLock(Duration timeout);

Попытка получить блокировку чтения для окружающего мьютекса. Если блокировка может быть получена без ожидания, блокировка приобретается, и возвращается true. Если нет, функция ожидает, пока блокировка не будет получена или время не превысит timeout, возвращая true, если блокировка была приобретена, и false, если функция истекла.

Параметры:
Duration timeout максимальное время ожидания блокировки
Возвращает:
true, если блокировка была приобретена, и false, если нет.
class Writer: object.Object.Monitor;

Этот класс может рассматриваться как мьютекс сам по себе и используется для переговоров о блокировке записи для окружающего мьютекса.

this();

Инициализирует объект-прокси писателя читательско-записного мьютекса.

@trusted void lock();

Приобретает блокировку записи для окружающего мьютекса.

@trusted void unlock();

Освобождает блокировку записи для окружающего мьютекса.

bool tryLock();

Попытка получить блокировку записи для окружающего мьютекса. Если блокировка может быть получена без ожидания, блокировка приобретается, и возвращается true. Если нет, блокировка не приобретается, и возвращается false.

Возвращает:
true, если блокировка была приобретена, и false, если нет.
bool tryLock(Duration timeout);

Попытка получить блокировку записи для окружающего мьютекса. Если блокировка может быть получена без ожидания, блокировка приобретается, и возвращается true. Если нет, функция ожидает, пока блокировка не будет получена или время не превысит timeout, возвращая true, если блокировка была приобретена, и false, если функция истекла.

Параметры:
Duration timeout максимальное время ожидания блокировки
Возвращает:
true, если блокировка была приобретена, и false, если нет.

© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/core_sync_rwmutex.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API