수색…
소개
스레드 와 상호 작용할 경우 스레드를 사용 하여 작업하면 동기화 기술이 필요할 수 있습니다. 이 항목에서는 이러한 문제를 해결하기 위해 표준 라이브러리가 제공하는 다양한 구조를 찾을 수 있습니다.
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 :: lock을 사용 하고 std :: lock을 호출하는 것이 가장 좋습니다.
std :: condition_variable_any, std :: cv_status
std::condition_variable
, std::condition_variable_any
의 일반화는 모든 유형의 BasicLockable 구조와 작동합니다.
조건 변수의 반환 상태로 std::cv_status
에는 두 가지 가능한 반환 코드가 있습니다.
- std :: cv_status :: no_timeout : 조건 변수에 통지 된 시간 초과가 없습니다.
- std :: cv_status :: no_timeout : 조건 변수가 시간 초과되었습니다.