サーチ…


前書き

作業スレッドは、スレッドが対話する場合、いくつかの同期技術が必要になる場合があります。このトピックでは、これらの問題を解決するために標準ライブラリによって提供されるさまざまな構造を見つけることができます。

std :: shared_lock

shared_lockは、一意のロックと組み合わせて使用​​して、複数のリーダーと排他的なライターを許可することができます。

#include <unordered_map>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <string>
#include <iostream>
    
class PhoneBook {
    public:
        string getPhoneNo( const std::string & name )
        {
            shared_lock<shared_timed_mutex> r(_protect);
            auto it =  _phonebook.find( name );
            if ( it == _phonebook.end() )
                return (*it).second;
            return "";
        }
        void addPhoneNo ( const std::string & name, const std::string & phone )
        {
            unique_lock<shared_timed_mutex> w(_protect);
            _phonebook[name] = phone;
        }
        
        shared_timed_mutex _protect;
        unordered_map<string,string>  _phonebook;
    };

std :: call_once、std :: once_flag

std::call_onceは競合するスレッドによって関数の実行を確実に一度保証します。タスクを完了できない場合は、 std::system_errorをスローします。

s td::once_flagと組み合わせて使用​​します。

#include <mutex>
#include <iostream>

std::once_flag flag;
void do_something(){
      std::call_once(flag, [](){std::cout << "Happens once" << std::endl;});
    
      std::cout << "Happens every time" << std::endl;
}

効率的なアクセスのためのオブジェクトロック。

オブジェクトに対して複数の操作を実行している間にオブジェクト全体をロックしたいことがよくあります。たとえば、 イテレータを使用してオブジェクトを調べたり変更したりする必要がある場合です。複数のメンバ関数を呼び出す必要があるときは、一般に個々のメンバ関数ではなくオブジェクト全体をロックする方が効率的です。

例えば:

class text_buffer
{
    // for readability/maintainability
    using mutex_type = std::shared_timed_mutex;
    using reading_lock = std::shared_lock<mutex_type>;
    using updates_lock = std::unique_lock<mutex_type>;

public:
    // This returns a scoped lock that can be shared by multiple
    // readers at the same time while excluding any writers
    [[nodiscard]]
    reading_lock lock_for_reading() const { return reading_lock(mtx); }

    // This returns a scoped lock that is exclusing to one
    // writer preventing any readers
    [[nodiscard]]
    updates_lock lock_for_updates() { return updates_lock(mtx); }

    char* data() { return buf; }
    char const* data() const { return buf; }

    char* begin() { return buf; }
    char const* begin() const { return buf; }

    char* end() { return buf + sizeof(buf); }
    char const* end() const { return buf + sizeof(buf); }

    std::size_t size() const { return sizeof(buf); }

private:
    char buf[1024];
    mutable mutex_type mtx; // mutable allows const objects to be locked
};

チェックサムを計算するとき、オブジェクトは読み込みのためにロックされ、オブジェクトから同時に読み込みたい他のスレッドが同時に行うことができます。

std::size_t checksum(text_buffer const& buf)
{
    std::size_t sum = 0xA44944A4;

    // lock the object for reading
    auto lock = buf.lock_for_reading();

    for(auto c: buf)
        sum = (sum << 8) | (((unsigned char) ((sum & 0xFF000000) >> 24)) ^ c);

    return sum;
}

オブジェクトを消去すると内部データが更新されるため、排他ロックを使用して処理を行う必要があります。

void clear(text_buffer& buf)
{
    auto lock = buf.lock_for_updates(); // exclusive lock
    std::fill(std::begin(buf), std::end(buf), '\0');
}

複数のロックを取得する場合は、常にすべてのスレッドに対して同じ順序でロックを取得するよう注意する必要があります。

void transfer(text_buffer const& input, text_buffer& output)
{
    auto lock1 = input.lock_for_reading();
    auto lock2 = output.lock_for_updates();

    std::copy(std::begin(input), std::end(input), std::begin(output));
}

注意:これはstd :: deferred :: lockstd :: lockを使って行うのが最適です

std :: condition_variable_any、std :: cv_status

std::condition_variablestd::condition_variable_anyの一般化は、どのタイプのBasicLockable構造でも機能します。

状態変数の戻り状態としてのstd::cv_statusは、2つの可能な戻りコードがあります。

  • std :: cv_status :: no_timeout:タイムアウトがなく、条件変数に通知されました
  • std :: cv_status :: no_timeout:条件変数のタイムアウト


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow