英語版
このページの英語版を見る

core.sync.rwmutex

読み取り/書き込みミューテックス・モジュールは、共有読み取りアクセスと相互排他的書き込みアクセスを維持するためのプリミティブを提供する。 相互に排他的な書き込みアクセスを維持するためのプリミティブを提供する。
Authors:
Sean Kelly
class ReadWriteMutex;
このクラスはミューテックスを表す、 しかし、ライタが入ると、他のすべてのリーダとライタはブロックされる。
このミューテックスは再帰的ではなく、データへのアクセスのみを保護するためのものであることに注意されたい。 だけであることに注意されたい。 また、デッドロック・チェックは行われていない。 デッドロック・チェックは行われていない。 デッドロック・チェックは行われていない。 その結果、このミューテックスを再帰的に取得しようとすると、デッドロックが発生する可能性がある。 このミューテックスを再帰的に取得しようとすると、呼び出し元がデッドロックに陥る可能性がある。 このミューテックスを再帰的に取得しようとすると、呼び出し元がデッドロック に陥る可能性がある。 しかし実際には、これは問題にはならない。 というのも、単にデータを保護するロックを保持したまま、未知のコードを深く呼び出すことは稀だからである。 を深く呼び出すことはめったにないからである。
Examples:
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つのreaderを同時に
    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
    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とwriterは互いに排他的である
    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とreaderは互いに排他的である
    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);

    // ポリシーは、キューに入れられたreaderとwritersのどちらが先に進むかを決定する
    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);
enum Policy: int;
このミューテックスが使用するポリシーを定義する。 現在、2つのポリシーが定義されている。 が定義されている。
1つ目は、ミューテックスを保持するリーダがいなくなるまでライタをキューに入れ、その後、ライタを1つずつ通過させる。 ライターを一人ずつ通過させる。 もしあるリーダがミューテックスを取得した場合 を取得した場合、そのリーダが優先される。
ライターがキューに入っていれば、2番目はリーダーをキューに入れる。 ライター は一度に一人ずつ通過し、ライターがいなくなると、キューに入れられたすべてのリーダーに警告が発せられる、 キューに入れられたすべての読者に警告が発せられる。
将来のポリシーでは、リーダとライタの優先順位をより均等なバランスにするかもしれない。 優先される。
PREFER_READERS
読者が優先される。 これは作家を飢えさせるかもしれない。
PREFER_WRITERS
作家が優先される。 これはリーダを飢えさせるかもしれない。
nothrow @safe this(Policy policy = Policy.PREFER_WRITERS);

shared nothrow @safe this(Policy policy = Policy.PREFER_WRITERS);
与えられたポリシーで読み取り/書き込みミューテックスオブジェクトを初期化する。
Parameters:
Policy policy 使用するポリシー。
Throws:
エラー時に SyncError を返す。
nothrow @property @safe Policy policy();

shared nothrow @property @safe Policy policy();
このミューテックスで使用されているポリシーを取得する。
Returns:
このミューテックスが使用するポリシー。
nothrow @property @safe Reader reader();

shared nothrow @property @safe shared(Reader) reader();
関連するミューテックスのリーダー・ロックを表すオブジェクトを取得する。
Returns:
リーダサブミューテックス。
nothrow @property @safe Writer writer();

shared nothrow @property @safe shared(Writer) writer();
関連付けられたミューテックスのライター・ロックを表すオブジェクトを取得する。
Returns:
ライター・サブミューテックス。
class Reader: object.Object.Monitor;
このクラスは、それ自体がミューテックスと見なすことができ、次のような用途に使用される。 このクラスは、それ自体がミューテックスと見なすことができ、ミューテックスを包含する読み取りロックのネゴシエーションに使用される。
nothrow @trusted this(this Q)()
if (is(Q == Reader) || is(Q == shared(Reader)));
読み取り/書き込みミューテックス・リーダー・プロキシ・オブジェクトを初期化する。
@trusted void lock();

shared @trusted void lock();
囲んでいるミューテックスの読み取りロックを獲得する。
@trusted void unlock();

shared @trusted void unlock();
囲んでいるミューテックスの読み取りロックを解放する。
@trusted bool tryLock();

shared @trusted bool tryLock();
包含するミューテックスの読み取りロックの獲得を試みる。 ブロックせずにロックを取得できる場合 ブロックせずにロックを取得できる場合、ロックが取得され、trueが返される。 が返される。 取得できない場合は、ロックは取得されず、falseが返される。
Returns:
ロックが獲得された場合はtrue、獲得されなかった場合はfalseが返される。
@trusted bool tryLock(Duration timeout);

shared @trusted bool tryLock(Duration timeout);
囲んでいるミューテックスに対する読み取りロックの獲得を試みる。ブロックせずにロックを取得できた場合は ブロックせずにロックを取得できた場合は、ロックを取得し、trueを返す。 が返される。そうでない場合、"関数"はロックが取得できるか、経過時間がロックを超えるまでブロックする。 ロックが取得できた場合はtrueが返され、取得できなかった場合はfalseが返される。 ロックが取得できた場合はtrueを、関数がタイムアウトした場合はfalseを返す。
Parameters:
Duration timeout ロックを待つ最大時間
Returns:
ロックが獲得された場合はtrue、獲得されなかった場合はfalse。
class Writer: object.Object.Monitor;
このクラスは、それ自体がミューテックスと見なすことができ、次のように使用される。 を囲むミューテックスに対して書き込みロックのネゴシエーションを行う。
nothrow @trusted this(this Q)()
if (is(Q == Writer) || is(Q == shared(Writer)));
読み取り/書き込みミューテックス・ライター・プロキシ・オブジェクトを初期化する。
@trusted void lock();

shared @trusted void lock();
囲んでいるミューテックスの書き込みロックを獲得する。
@trusted void unlock();

shared @trusted void unlock();
囲んでいるミューテックスの書き込みロックを解放する。
@trusted bool tryLock();

shared @trusted bool tryLock();
囲んでいるミューテックスの書き込みロックの獲得を試みる。 ブロックせずにロックを取得できる場合 ブロックせずにロックを取得できる場合、ロックが取得され、trueが返される。 が返される。 取得できない場合は、ロックは取得されず、falseが返される。
Returns:
ロックが取得された場合はtrue、取得されなかった場合はfalseが返される。
@trusted bool tryLock(Duration timeout);

shared @trusted bool tryLock(Duration timeout);
ミューテックスを包含する書き込みロックの獲得を試みる。ブロックせずにロックを取得できた場合は ブロックせずにロックを取得できた場合は、ロックが取得され、trueが返される。 が返される。そうでない場合、"関数"はロックが取得できるまでブロックする。 ロックが取得できた場合はtrueが返され、取得できなかった場合はfalseが返される。 ロックが取得できた場合はtrueを、関数がタイムアウトした場合はfalseを返す。
Parameters:
Duration timeout ロックを待つ最大時間
Returns:
ロックが取得された場合はtrue、取得されなかった場合はfalse。