一、原子变量和智能指针
在前面学习时提到过智能指针本身不是线程安全的,因为虽然其计数器是线程安全控制但数据不是,这也就是说其在多线程中赋值时,会产生冲突。而原子变量恰恰能够解决这个问题,不过在早先的c++标准中,原子变量不支持智能指针,所以要实现多线程间数据的安全控制,要么使用锁,要么使用全局的非成员原子操作(std::atomic_load(), atomic_store()等)。
但是,c++20中,原子操作增加了对智能指针类型的支持,这样就可以安全快速的控制智能指针在不同线程间的数据操作了。
二、原子智能指针
在c++的文档中可以看到:
template<class U>
struct atomic<std::shared_ptr<U>>; (C++20 起)
template<class U>
struct atomic<std::weak_ptr<U>>; (C++20 起)
目前来看相关的代码实现仍然是使用了CAS的方式,更具体的得需要看实现库的具体的源码。
三、应用例程
看一个例程:
template<typename T>
class concurrent_stack {
struct Node {
T t;
shared_ptr<Node> next;
};
atomic_shared_ptr<Node> head;
// C++11中使用非"atomic_" 就必须使用前面提到的孤立函数std::tomic_load 等
public:
class reference {
shared_ptr<Node> p;
<snip>
};
auto find(T t) const {
auto p = head.load(); // C++11使用atomic_load(&head)
while (p && p->t != t)
p = p->next;
return reference(move(p));
}
auto front() const {
return reference(head);
}
void push_front(T t) {
auto p = make_shared<Node>();
p->t = t; p->next = head;
while (!head.compare_exchange_weak(p->next, p)){
} // C++11使用 atomic_compare_exchange_weak(&head, &p->next, p); }
void pop_front() {
auto p = head.load();
while (p && !head.compare_exchange_weak(p, p->next)) {
} // C++11使用atomic_compare_exchange_weak(&head, &p, p->next);
}
};
这个例程是Herb Sutter 的 N4162 论文中的一段,c++的文档中目前还没有看到。
四、总结
按照c++文件档中所说,std::shared_ptr的控制块是安全,但如果使用其访问非const的成员函数则会出现数据竞争,也就是数据冲突。这样说来,这个原子智能指针的用处还是不小,毕竟一般操作智能指针还是以操作函数居多。其实这也是c++减少孤立函数,扩大现有功能的范围的一种进步。不断内聚,去除耦合。这样也符合一般人们的习惯。
换句话说,多一些普遍适用,少一些特例应用。