より多くのC ++ 11のstd内の1つのスレッドのタイトルの条件変数より観点から::利用のcondition_variableと原則

今、以下のようなペンの質問があります。

二つのスレッド、1つのスレッドのループ出力がありA、別のスレッドのループ出力Bコンソールでは、これら二つのスレッドに安定した出力を作成する方法は、ABABAB…

あまり考えずに、私たちは確かに、変数の兆候を定義するisTurnAisTurnAとしてtrue出力A、出力同じトークンBだけステートマシンに従って、それが最も簡単な有限状態機械の一つであり、そして確かな答えを同意するものとします。isTurnA保護するデータなので、アトミック変数またはミューテックスを共有している、ミューテックスがここで使用されstd::mutex、コードは次のとおりです。

class TypeAB
{
public:
    TypeAB() : _isTurnA(true) {}
    ~TypeAB()
    {
        _threadA.join();
        _threadB.join();
    }
    void PrintAB()
    {
        _threadA = std::thread(&TypeAB::TypeA, this);
        std::this_thread::sleep_for(std::chrono::seconds(2));
        _threadB = std::thread(&TypeAB::TypeB, this);
    }
private:
    std::mutex _mutex;
    bool _isTurnA;

    std::thread _threadA;
    std::thread _threadB;

    void TypeB()
    {
        for (int cnt = 0; cnt < 10; std::this_thread::sleep_for(std::chrono::seconds(3)))
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (; _isTurnA; )
            {
                lock.unlock();
                lock.lock();
            }
            std::cout << std::this_thread::get_id() << " - B : " << cnt++ << std::endl;
            _isTurnA = true;
        }
    }

    void TypeA()
    {
        for (int cnt = 0; cnt < 10; std::this_thread::sleep_for(std::chrono::seconds(1)))
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (; !_isTurnA; )
            {
                lock.unlock();
                lock.lock();
            }
            std::cout << std::this_thread::get_id() << " - A : " << cnt++ << std::endl;
            _isTurnA = false;
        }
    }
};

このコードは実行されているが、次のサイクルを見ています:

for (; !_isTurnA; )
{
    lock.unlock();
    lock.lock();
}

別のスレッドがこれを行うがかかり効率のように、ロックを取得する機会を持っているのでという、ロックを解除するために続けています。その後、我々は、ブロッキング操作に来ます:

for (; !_isTurnA; )
{
    lock.unlock();
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    lock.lock();
}

これが問題をもたらすだろうと同じように、それだけで完了し、ロックへのアクセスをブロックすることがあり、この時間は、ちょうど別のスレッドを設定しisTurnA、このような状況は、現在のスレッドが複数回ブロックさせます。したがって、ブロックの時間のバランスを取る、この困難な時期を遮断することが短すぎる、その後、スピンで、違いはありません。時間を遮断することが長すぎる、それはないタイムリーな問題をスレッドにつながります。

これは戻っていたのイベントイベント(条件変数パッケージ上)C ++:次のような方法、それが動作することを、条件変数電車の中でその例

for (; !_isTurnA; )
{
    lock.unlock();
    // 线程阻塞于此,等待一个信号,有这个信号就不阻塞了
    lock.lock();
}

特定には見ることができます(条件変数パッケージ上)C ++イベントイベントで条件変数を導入しました。ここではその質問への答えは、標準的なマルチスレッドの道である、次のとおりです。

#include <bits/stdc++.h>

class TypeAB
{
public:
    ~TypeAB()
    {
        _threadA.join();
        _threadB.join();
    }
    void PrintAB()
    {
        _threadA = std::thread(&TypeAB::TypeA, this);
        std::this_thread::sleep_for(std::chrono::seconds(2));
        _threadB = std::thread(&TypeAB::TypeB, this);
    }
private:
    std::mutex _mutex;
    std::condition_variable _condi;
    bool _isTurnA = true;

    std::thread _threadA;
    std::thread _threadB;

    void TypeB()
    {
        for (int cnt = 0; cnt < 10; std::this_thread::sleep_for(std::chrono::seconds(3)))
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _condi.wait(lock, [this] () -> bool { return !_isTurnA; });
            std::cout << std::this_thread::get_id() << " - B : " << cnt++ << std::endl;
            _isTurnA = true;
            lock.unlock();

            _condi.notify_one();
        }
    }

    void TypeA()
    {
        for (int cnt = 0; cnt < 10; std::this_thread::sleep_for(std::chrono::seconds(1)))
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _condi.wait(lock, [this] () -> bool { return _isTurnA; });
            std::cout << std::this_thread::get_id() << " - A : " << cnt++ << std::endl;
            _isTurnA = false;
            lock.unlock();

            _condi.notify_one();
        }
    }
};

int main()
{
    TypeAB().PrintAB();
    return 0;
}

今見て取りstd::condition_variable、ソースコードのセクションを:

// VC14的mutex头文件
class condition_variable
{ // class for waiting for conditions
  public:
    typedef _Cnd_t native_handle_type;

    condition_variable()
    { // construct
        _Cnd_init_in_situ(_Mycnd());
    }

    ~condition_variable() _NOEXCEPT
    { // destroy
        _Cnd_destroy_in_situ(_Mycnd());
    }

    condition_variable(const condition_variable &) = delete;
    condition_variable &operator=(const condition_variable &) = delete;

    void notify_one() _NOEXCEPT
    { // wake up one waiter
        _Cnd_signalX(_Mycnd());
    }

    void notify_all() _NOEXCEPT
    { // wake up all waiters
        _Cnd_broadcastX(_Mycnd());
    }

    void wait(unique_lock<mutex> &_Lck)
    { // wait for signal
        _Cnd_waitX(_Mycnd(), _Lck.mutex()->_Mymtx());
    }

    template <class _Predicate>
    void wait(unique_lock<mutex> &_Lck, _Predicate _Pred)
    { // wait for signal and test predicate
        while (!_Pred())
            wait(_Lck);
    }
}

以下のコード検証の質問:

  • wait二勧告の文言は、エラー覚醒を防ぐことができます
  • 条件変数は、使用するロックを一致させる必要がある、とだけすることができstd::unique_lock、二つの理由からstd::unique_lockロック解除メンバ関数が正確に適合条件変数を働きがある; RAIIモードは、あなたが例外安全性を保証することができます
  • 条件変数は、構成およびアサイン設定を(2つのコンストラクタが除去される)をコピーすることができないだけでなく、ああ(右辺値コンストラクタが削除されていない)、移動させることができるstd::condition_variable構成std::future予示を
299元記事公開 ウォンの賞賛353 ビューに45万+を

おすすめ

転載: blog.csdn.net/FlushHip/article/details/88311749