Help us understand the problem. What is going on with this article?

マルチスレッドのConditionについて

More than 1 year has passed since last update.

はじめに

core.sync.condition.Condition
「え?ただのConditionだよ?知ってるよね?」みたいに書かれてる。
つらい。

Conditionとは

Java由来?のマルチスレッドの同期システムです。Javaとか滅せ。
コンストラクタの引数にしたMutexを使って、ロックの解除を待ったり、通知を待ったりします。
Conditionでwaitした場合、Mutexがロックされていなくて、かつConditionに通知(notify)されるまでスレッドを停止します。

例(1) ロック中にwaitした場合

Mutexをロックしているときにwaitすると、そのMutexのロックを解除して、待機状態に入ります。別スレッドがMutexをロックすると、notifyされても、Mutexがロック解除されるまでは待機を維持します。

import std.stdio, std.parallelism, core.thread, core.sync.condition, core.sync.mutex;

void main()
{
    auto cond = new Condition(new Mutex);

    //     000    100    200    300    400    500    600 [ms]
    // 1:  1xxxxxxxxxxxxxooooooo-------6xxxxxx7     8!
    // 2:         2------xxxxxx3!4xxxx5oooooooooooooo9
    // 【凡例】
    //     x : ロック中
    //     - : 他のロック解除待ち
    //     o : 他からの通知待ち
    //     ! : 通知

    //     000    100    200    300    400    500    600 [ms]
    // 1:  1xxxxxxxxxxxxxooooooo-------6xxxxxx7     8!
    taskPool.put(task(
    {
        Thread.sleep(0.msecs);
        writeln(1);
        cond.mutex.lock();
        Thread.sleep(200.msecs);

        // ここで一度ロックが外れる
        // →3での通知を受けて再度ロックを試みて解除を待つ
        //   →5でロック解除されて制御が戻る
        cond.wait();

        writeln(6);
        Thread.sleep(100.msecs);

        writeln(7);
        cond.mutex.unlock();

        Thread.sleep(100.msecs);
        writeln(8);
        cond.notify();
    }));
    //     000    100    200    300    400    500    600 [ms]
    // 2:         2------xxxxxx3!4xxxx5oooooooooooooo9
    taskPool.put(task(
    {
        Thread.sleep(100.msecs);

        writeln(2);
        cond.mutex.lock();

        Thread.sleep(100.msecs);
        writeln(3);
        cond.notify();
        writeln(4);
        Thread.sleep(100.msecs);
        writeln(5);
        // ここで一度ロックが外れる
        // →8での通知を受けて再度ロックを試みてロック成功
        cond.wait();

        writeln(9);
        cond.mutex.unlock();
    }));
    taskPool.finish();
}

例(2) ロック解除中にwaitした場合

ロック解除中にwaitした場合、ほかのスレッドからnotifyされるまで待機します。

import std.stdio, std.parallelism, core.thread,
       core.sync.condition, core.sync.mutex;

void main()
{
    auto cond = new Condition(new Mutex);

    //     000    100    200    300    400    500    600 [ms]
    // 1:  1ooooooooooooo-------6xxxxxx7     8!
    // 2:         2xxxxx3!4xxxx5oooooooooooooox9
    // 【凡例】
    //     x : ロック中
    //     - : 他のロック解除待ち
    //     o : 他からの通知待ち
    //     ! : 通知

    //     000    100    200    300    400    500    600 [ms]
    // 1:  1ooooooooooooo-------6xxxxxx7     8!
    taskPool.put(task(
    {
        Thread.sleep(0.msecs);
        writeln(1);

        // 通知待ち
        // →3での通知を受けてロックを試みて解除を待つ
        //   →5でロック解除されて制御が戻る
        cond.wait();

        writeln(6);
        Thread.sleep(100.msecs);

        writeln(7);
        cond.mutex.unlock();

        Thread.sleep(100.msecs);
        writeln(8);
        cond.notify();
    }));
    //     000    100    200    300    400    500    600 [ms]
    // 2:         2xxxxx3!4xxxx5oooooooooooooox9
    taskPool.put(task(
    {
        Thread.sleep(100.msecs);

        writeln(2);
        cond.mutex.lock();

        Thread.sleep(100.msecs);
        writeln(3);
        cond.notify();
        writeln(4);
        Thread.sleep(100.msecs);
        writeln(5);
        // ここで一度ロックが外れる
        // →8での通知を受けて再度ロックを試みてロック成功
        cond.wait();

        writeln(9);
        cond.mutex.unlock();
    }));
    taskPool.finish();
}

D言語特有の問題

Conditionは性質上、当たり前のようにスレッド間で共有される資源です。つまり、sharedストレージクラスにしたくなる時があります。
しかしながら、Condition(をはじめとするcore.sync.*のモジュール)はsharedなメンバ関数を提供していません。
今我々にできる最良の手順は、castによってsharedを外してしまうことです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした