8

次のようなクラスがあるとします (実際にはちょうどこのサイズです)。

class K
{
public:

    long long get_x() const; // lock m_mutex in shared/read-only mode

    void update( long long w ); // lock m_mutex with a unique_lock

private:
    long long m_a;
    long long m_b;
    long long m_c;
    long long m_x;
    double m_flow_factor;

    mutable boost::shared_mutex m_mutex;
};

ご覧のとおり、これはスレッドセーフである必要があります。更新関数は、一度に 1 つのスレッドによって呼び出されます。不明ですが、1 つのスレッドのみ (保証されます) ですが、アクセサーは同時に複数のスレッドによって呼び出される可能性があります。

update 関数はすべての値を変更しており、非常に頻繁に呼び出されます (1 秒間に 100 回)。ご想像のとおり、現在の実装では多くのロックが発生します。

ロックを回避し、このコードをより効率的にするために std::atomic を使用することを検討していました。ただし、値を一緒に更新するには update 関数が本当に必要です。したがって、代わりに次のようなことを検討しています。

class K
{
public:

    long long get_x() const
    { return data.load().x; }

    void update( long long w )
    {
        auto data_now = data.load();
        // ... work with data_now
        data.store( data_now );
    }

private:
    struct Data {
    long long a;
    long long b;
    long long c;
    long long x;
    double flow_factor;
    };
    std::atomic<Data> data;
};

std::atomic についての私の現在の理解は、このコードが前のものよりも読みやすい場合でも (どこにでもロック宣言がないため)、K::Data 構造体が「大きい」ため、std::atomic通常のミューテックスロックで実装されるだけです(とにかく、最初の実装よりも高速になるはずはありません)。

私は正しいですか?

4

3 に答える 3

12

そのような構造体の std:atomic の特殊化には内部ロックが含まれるため、何も得られず、排他ロックがあったため、以前にはなかったロードとストアの間のデータ競合も発生します。以前のバージョンでは、ブロック全体(私は推測しますか?)の周り。

また、shared_mutex では、通常のミューテックスと shared_mutex を比較してプロファイリングするのが賢明かもしれません。通常のミューテックスの方がパフォーマンスが優れていることがわかります (すべては、ロックを保持している時間によって異なります)。

shared_mutex の利点は、読み取りのためにロックが長時間保持されていて、書き込みがほとんどない場合にのみ見られます。それ以外の場合、shared_mutex に伴うオーバーヘッドにより、通常のミューテックスよりも得られる利点が失われます。

于 2012-12-23T05:33:27.557 に答える
1

std::atomic は必ずしも std::mutex より遅いわけではありません。たとえば、MSVC 14.0 では、std::atomic.store の実装は次のようになります。

inline void _Atomic_copy(
volatile _Atomic_flag_t *_Flag, size_t _Size,
    volatile void *_Tgt, volatile const void *_Src,
        memory_order _Order)
{   /* atomically copy *_Src to *_Tgt with memory ordering */
_Lock_spin_lock(_Flag);
_CSTD memcpy((void *)_Tgt, (void *)_Src, _Size);
_Unlock_spin_lock(_Flag);
}

inline void _Lock_spin_lock(
volatile _Atomic_flag_t *_Flag)
{   /* spin until _Flag successfully set */
while (_ATOMIC_FLAG_TEST_AND_SET(_Flag, memory_order_acquire))
    _YIELD_PROCESSOR;
}

スピン ロックが適切な std::mutex よりも高速であるという保証はありません。それはあなたが何をしているのかに依存します。しかし、std::atomic は、std::mutex と比較して常に次善のソリューションであるとは限りません。

于 2017-09-21T06:34:23.240 に答える