5

私の質問は簡単です。C++11 にはstd::mutexandstd::lock_guardとがありstd::unique_lockます。

これらのクラスを使用する通常の方法は、std::mutexいずれかのロックを介してロックすることです。これにより、例外のスローによるミューテックスのリークが防止されます。

{
   std::lock_guard<std::mutex> l(some_mutex);
   //Cannot leak mutex.
}

なぜ公開されているのですかstd::mutex::lockstd::mutex::unlockそれは間違った使い方を要求します:

{ 
     some_mutex.lock();
     //Mutex leaked due to exception.
     some_mutex.unlock();
}

ロック操作を非公開にstd::lock_guardstd::unique_lock、友達にstd::mutexして、プライベートにする方が安全ではないでしょうか? std::mutexこれにより、安全でない使用を防ぐことができます。

この設計について私が推測できる唯一の理由は、私が自分のロックを持っている場合、std::mutex自分のロックをstd::mutex. これが、これらのメンバー関数を公開する主な理由ですか?

4

2 に答える 2

13

この設計上の決定の根拠は、N2406に記載されています。

ブーストとは異なり、mutex には lock()、unlock() などのパブリック メンバー関数があります。これは、主要な目標の 1 つをサポートするために必要です: ユーザー定義の mutex は、標準定義のロックで使用できます。ユーザー定義のミューテックスを実装するためのインターフェイスがなければ、標準定義のロックがユーザー定義のミューテックスと通信する方法はありません。

これが書かれた時点では、boost::mutex は boost::scoped_lock でのみロックおよびロック解除できました。

これで、 を書くことができます。メンバとmy::mutexを提供する限り、あなたは と同じくらい一流の市民です。あなたのクライアントは、何が何なのかわからなくても、 を使うのと同じくらい簡単に を使うことができます。lock()unlock()my::mutexstd::mutexstd::unique_lock<my::mutex>std::unique_lock<std::mutex>std::unique_lockmy::mutex

の動機付けとなる実際の例は、C++1y (y == 4 であることが望ましい)ドラフト標準my::mutexで現在提案されているです。 にはメンバーがあり、排他モードのロックおよびロック解除用です。そして、クライアントが期待どおりに使用するときに相互作用します。std::shared_mutexstd::shared_mutexlock()unlock()std::unique_lockstd::unique_lock<std::shared_mutex>

そしてshared_mutex、この汎用インターフェイスを利用できる他の唯一の動機ミューテックスであると思われるかもしれない場合に備えて、別の実際の例を次に示します: :-)

template <class L0, class L1>
void
lock(L0& l0, L1& l1)
{
    while (true)
    {
        {
            unique_lock<L0> u0(l0);
            if (l1.try_lock())
            {
                u0.release();
                break;
            }
        }
        this_thread::yield();
        {
            unique_lock<L1> u1(l1);
            if (l0.try_lock())
            {
                u1.release();
                break;
            }
        }
        this_thread::yield();
    }
}

これは、デッドロックの危険なしに、2 つの BasicLockables を同時に (例外的に安全な方法で) ロックする方法の基本的なコードです。反対の多くの批判にもかかわらず、このコードは非常に 効率的です。

上記のコードの行に注意してください。

            unique_lock<L0> u0(l0);

このアルゴリズムでは、型が何であるかはわかりませんL0lock()しかし、それがサポートしている限りunlock()(もちろんtry_lock()そうです)、すべてがクールです。 、おそらくまたはさらに、またはおそらくさらにL0の別のインスタンス化でさえあるかもしれません。unique_lockunique_lock<my::mutex>unique_lock<std::shared_mutex>std::shared_lock<std::shared_mutex>

それはすべてうまくいきます。そしてすべては、合意された と のパブリック インターフェイスを除いて、とstd::unique_lockの間に親密な関係がないためです。std::mutexlock()unlock()

于 2013-11-04T03:21:52.880 に答える
3

Jerry Coffin が指摘したように、実際の委員会のメンバーが同意しない限り推測することしかできませんが、私の推測では、彼らは柔軟性を備えたインターフェイスを設計し、独自の方法で拡張できることを念頭に置いていたのでしょう。可能性のあるすべてのクラスを のフレンドにする代わりにstd::mutex、必要な操作を実行するインターフェイスを公開することで、誰か (ブーストの貢献者など) がやって来て、それを使って何かを行うための新しいより良い方法を見つけることができます。インターフェイスが非表示の場合、それは不可能です。

于 2013-11-04T03:22:52.843 に答える