Vulkan 算是入门了,但是如果想要更深入的理解其 Command 的机制,还是有必要巩固一下并发编程的基础。所以就买了一本《C++ 并发编程实战 (第二版)》。看了三分之一了,但是觉得光看是没有意义的,重写示例算是必修课!所以边做笔记边实践吧 #109
class background_task
{
public:
void operator()() const
{
do_something();
do_something_else();
}
};
background_task f;
std::thread my_thread(f);
class X
{
public:
void do_lengthy_work();
};
X my_x;
std::thread t(&X::do_lengthy_work,&my_x);
Foo f;
auto hello = std::mem_fn(&Foo::say_hello);
hello(f);
auto count_num = std::mem_fn(&Foo::count_num);
count_num(f, 2);
std::mutex 的实例来创建互斥,调用成员函数 lock() 对其加锁,调用 unlock() 解锁。
std::lock_guard<>,针对互斥类融合实现了 RAII 手法:在构造时给互斥加锁,在析构时解锁,从而保证互斥总被正确解锁。
std::lock_guard<> 模板参数列表可以忽略std::scoped_lock,它是增强版的 lock_guard。
std::scoped_lock guard(some_mutex);std::mutex some_mutex;
...
std::scoped_lock guard(some_mutex);
std::shared_ptr是不错的选择std::lock(lhs.m, rhs.m); std::scoped_lock 后,就不需要 std::lock 和 std::adopt_lock 实现互斥void swap(X& lhs, X& rhs)
{
if(&lhs==&rhs)
return;
std::scoped_lock guard(lhs.m, rhs.m);
swap(lhs.some_detail,rhs.some_detail);
}
避免嵌套锁
一旦持锁,就须避免调用由用户提供的程序接口
依从固定顺序获取锁
按层级加锁
try_lock(),但它相当简单:
将准则推广到锁操作以外
std::unique_lock<> 模板。它与 std::lock_guard<> 一样,也是一个依据互斥作为参数的类模板,并且以 RAII 手法管理锁,不过它更灵活一些std::unique_lock<> 放宽了不变量的成立条件,因此它相较 std::lock_guard<> 更灵活一些std::unique_lock 对象不一定始终占有与之关联的互斥
std::adopt_lock 实例,借此指明 std::unique_lock 对象管理互斥上的锁;std::defer_lock 实例,从而使互斥在完成构造时处于无锁状态,等以后有需要时才在 std::unique_lock 对象(不是互斥对象)上调用 lock() 而获取锁,或把std::unique_lock 对象交给 std::lock() 函数加锁std::unique_lock 占用更多的空间,也比 std::lock_guard 略慢
std::unique_lock 对象可以不占有关联的互斥,具备这份灵活性需要付出代价:需要存储并且更新互斥信息。std:: unique_lock 替换 std::lock_guard ,便会导致轻微的性能损失
std::lock_guard 已经能满足所需,我建议优先采用std::unique_lock 可用场景
std::scoped_lock 可代替 std::lock_guard 但不能取代 std::unique_lock ,他们的作用不同std::unique_lock 实例不占有与之关联的互斥,所以随着其实例的转移,互斥的归属权可以在多个 std::unique_lock 实例之间转移。
std::unique_lock 属于可移动却不可复制的型别std::unique_lock<std::mutex> get_lock()
{
extern std::mutex some_mutex;
std::unique_lock<std::mutex> lk(some_mutex);
prepare_data();
return lk;
}
void process_data()
{
std::unique_lock<std::mutex> lk(get_lock());
do_something();
}
std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;
void init_resource()
{
resource_ptr.reset(new some_resource);
}
void foo()
{
std::call_once(resource_flag, init_resource);
resource_ptr->do_something();
}
class my_class;
my_class& get_my_class_instance()
{
//利用局部静态变量,实现线程安全
static my_class instance;
return instance;
}
std::shared_mutex 和 std::shared_timed_mutex。std::shared_timed_mutex ,而 C++11 标准库都没有。std::shared_mutex 和 std::shared_timed_mutex 的区别在于,后者支持更多操作。
std::shared_mutex,其在某些平台上可能会带来性能增益。#include
#include
#include
#include
class dns_entry
{};
class dns_cache
{
std::map<std::string,dns_entry> entries;
std::shared_mutex entry_mutex;
public:
dns_entry find_entry(std::string const& domain)
{
std::shared_lock<std::shared_mutex> lk(entry_mutex);
std::map<std::string,dns_entry>::const_iterator const it = entries.find(domain);
return (it==entries.end())?dns_entry():it->second;
}
void update_or_add_entry(std::string const& domain, dns_entry const& dns_details)
{
std::lock_guard<std::shared_mutex> lk(entry_mutex);
entries[domain]=dns_details;
}
};
int main()
{}
std::recursive_mutex ,其工作方式与 std::mutex 相似,不同之处是,其允许同一线程对某互斥的同一实例多次加锁。std::recursive_mutex
std::mutex 便会导致未定义行为。