如何进行线程安全shared_ptr修改和访问?

How to do thread safe shared_ptr modification and access?

本文关键字:修改 访问 ptr 何进行 线程 安全 shared      更新时间:2023-10-16

目标:我想修改内部信息,并尽可能快地从多个线程同步访问此信息

我简化了下面的代码,但这就是我试图实现这一点的方式。

我有 2 个共享指针。

一个叫m_mutable_data,另一个叫m_const_data

m_mutable_data以链保护方式更新。m_const_data每60年代也以链保护的方式更新m_mutable_data内容。

这是使用新数据重置共享指针m_const_data唯一位置。m_const_data由许多线程同步读取,每秒 1000+ 次。

法典

class black_list_container : public std::enable_shared_from_this<black_list_container>
{
struct meta_data
{
bool blacked;
}
struct black_list_data
{
std::unordered_map<uint32_t,meta_data> data;
}
public:
#pragma optimize( "", off )
bool is_blacked(uint32_t id) 
{
// This call is called from many different threads (1000+ calls per second)
// should be synchronous and as fast as possible
auto c = m_const_data;
return c->data[id].blacked;
}
#pragma optimize( "", on )
#pragma optimize( "", off )
void update_const_data() 
{
// Called internaly by timer every 60s to update m_const_data with contents of m_mutable_data
// Guarded with strand
m_strand->post([self{shared_from_this()}]{
auto snapshot = new black_list_data();
snapshot->data = m_mutable_data->data;
m_const_data.reset(snapshot);
});
}
#pragma optimize( "", on )

private:
void internal_modification_mutable_data()
{
// Called internaly by different metrics
// Guarded with strand
m_strand->post([self{shared_from_this()}]{
// .... do some modification on internal m_mutable_data
});
}
boost::asio::io_context::strand m_strand;
std::shared_ptr<black_list_data> m_mutable_data;
std::shared_ptr<black_list_data> m_const_data;
};

非常非常很少此代码在线在方法"is_blacked"中崩溃

auto c = m_const_data;

这是回溯

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./STRATUM-01'.
Program terminated with signal 6, Aborted.
#0  0x00007fe09aaf1387 in raise () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 libgcc-4.8.5-39.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64
(gdb) bt
#0  0x00007fe09aaf1387 in raise () from /lib64/libc.so.6
#1  0x00007fe09aaf2a78 in abort () from /lib64/libc.so.6
#2  0x00007fe09ab33ed7 in __libc_message () from /lib64/libc.so.6
#3  0x00007fe09ab3c299 in _int_free () from /lib64/libc.so.6
#4  0x00000000005fae36 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x7fe0440aeaa0) at /opt/rh/devtoolset-7/root/usr/include/c++/7/bits/shared_ptr_base.h:154
#5  0x00000000006b9205 in ~__shared_count (this=<synthetic pointer>, __in_chrg=<optimized out>) at /opt/rh/devtoolset-7/root/usr/include/c++/7/bits/shared_ptr_base.h:684
#6  ~__shared_ptr (this=<synthetic pointer>, __in_chrg=<optimized out>) at /opt/rh/devtoolset-7/root/usr/include/c++/7/bits/shared_ptr_base.h:1123
#7  ~shared_ptr (this=<synthetic pointer>, __in_chrg=<optimized out>) at /opt/rh/devtoolset-7/root/usr/include/c++/7/bits/shared_ptr.h:93
#8  black_list_container_impl::is_blacked (this=0x7fe08c287e50, id=23654) at /var/lib/jenkins/workspace/validator/src/black_list_container.cpp:69

我不确定为什么在帧 #7 中调用shared_ptr的破坏

显然我没有实现我的目标,所以请引导我进入以线程安全的方式实际实现我的目标的模式。

我知道我本可以使用

std::atomic<std::shared_ptr<black_list_data>> m_const_data;

但是,这不会影响从许多不同线程读取时的性能吗?

我想我在这篇文章中找到了问题的答案 原子智能指针.

所以我必须将代码更改为update_const_data()

auto snapshot = std::make_shared<black_list_data>();
snapshot->data = m_mutable_data->data;
std::atomic_store(&m_const_data, snapshot);

和代码is_blacked()

auto c = std::atomic_load(&m_const_data);