6

ご存知のように、条件変数は、誤ったウェイクアップを回避するためにサイクルで呼び出す必要があります。このような:

while (not condition)
    condvar.wait();

別のスレッドが待機中のスレッドをウェイクアップする場合は、条件フラグをtrueに設定する必要があります。例えば:

condition = true;
condvar.notify_one();

このシナリオで条件変数がブロックされる可能性はありますか?

1)待機中のスレッドは条件フラグをチェックし、それがFALSEに等しいことを検出したため、condvar.wait()ルーチンに入ります。

2)ただし、この直前(ただし、条件フラグのチェック後)に、待機中のスレッドがカーネルによってプリエンプトされます(タイムスロットの有効期限などのため)。

3)このとき、別のスレッドが待機中のスレッドに状態を通知したいと考えています。条件フラグをTRUEに設定し、呼び出しますcondvar.notify_one();

4)カーネルスケジューラが最初のスレッドを再度実行すると、condvar.wait()ルーチンに入りますが、通知はすでに欠落しています。

したがって、condvar.wait()ウェイクアップ通知がなくなったため、条件フラグがTRUEに設定されていても、待機中のスレッドを終了することはできません。

出来ますか?

4

4 に答える 4

16

アトミックに状態を更新して変更を通知するために、条件変数をミューテックスと組み合わせて使用​​する必要があるのはまさにそのためです。完全なコードは次のようになります。

unique_lock<mutex> lock(mutex);
while (not condition)
    condvar.wait(lock);

および他のスレッドの場合:

lock_guard<mutex> lock(mutex);
condition = true;
condvar.notify_one();
于 2013-02-25T17:25:35.507 に答える
4

あなたは小さな部分が欠けている例を挙げていますが、それが正しく行われた場合にそれが不可能な理由を説明しています:

while (not condition) // when you check condition mutex is locked
    condvar.wait( mutex ); // when you wait mutex is unlocked

そのため、同じミューテックス ロックで条件を true に変更すると、この状況は発生しません。

于 2013-02-25T17:21:29.083 に答える
-2

はい (私は 2012 年 12 月にこれをテストしました)、少し前に思いついた解決策があります。「Flare」クラス: スピン ロックを使用しますが、これに費やされる時間は最小限であることに注意してください。

宣言 (hpp):

class Flare
{
public:
/**
\brief Flare's constructor.
\param fall_through_first, will skip the first wait() if true.
*/
Flare(bool fall_through_first = false);


/**
\brief Flare's destructor.

Takes care of removing the object of this class.
*/
~Flare();


/**
\brief Notifies the same object of availability.

Any thread waiting on this object will be freed,
and if the thread was not waiting, it will skip
wait when it iterates over it.
*/
void notify();


/**
\brief Wait until the next notification.

If a notification was sent whilst not being
inside wait, then wait will simply be skipped.
*/
void wait();


private:
    std::mutex m_mx; // Used in the unique_lock,
    std::unique_lock<std::mutex> m_lk; // Used in the cnd_var
    std::condition_variable m_cndvar;

    std::mutex m_in_function, n_mx; // protection of re-iteration.
    bool m_notifications;

};

実装/定義 (cpp):

#include "Flare.hpp"


// PUBLIC:

Flare::Flare(bool fall_through_first)
:
m_lk(m_mx),
m_notifications(!fall_through_first)
{}

Flare::~Flare()
{}

void Flare::notify()
{
    if (m_in_function.try_lock() == true)
    {
        m_notifications = false;
        m_in_function.unlock();
    }
    else // Function is waiting.
    {
        n_mx.lock();
        do
        {
            m_notifications = false;
            m_cndvar.notify_one();
        }
        while (m_in_function.try_lock() == false);
        n_mx.unlock();
        m_in_function.unlock();
    }
}

void Flare::wait()
{
    m_in_function.lock();
    while (m_notifications)
        m_cndvar.wait(m_lk);
    m_in_function.unlock();
    n_mx.lock();
    m_notifications = true;
    n_mx.unlock();
}
于 2013-02-25T17:21:24.603 に答える