客户端持有一个指向值 say 的共享指针double
,服务器通过持有 a 在另一个分离线程上更新该值weak_pointer
,服务器检查该值是否weak_pointer
过期,如果未过期,则从安全向量中删除它。我怀疑这不起作用,因为在我的读取(我认为它是线程安全的,因为我想象它指的是 的原子计数器)和我的值更新之间shared_ptr
可能会从客户端被破坏。有没有办法让检查和函数在破坏之前更新值?我是说:expired()
shared_ptr
expired()
lambda
struct server
{
public:
static void subscribe(const std::shared_ptr<double>& d)
{
m_values.safe_push_back(d); //safely pushes back in the vector
}
void update()
{
auto updater = [](std::weak_ptr<double>& wd)
{
if(wd.expired()) wd = nullptr;
else *wd += 2.0; //This is not thread safe I guess?
};
m_values.safe_remove_all(nullptr);
m_values.safe_visit(updater);
};
private:
static safe_vector<std::weak_ptr<double>> m_values;
}
struct client
{
void subcribe_sleep_print(const double random_seconds)
{
std::shared_ptr<double> d = std::make_shared<double>(0.0); //for the sake of the example assume we create subscribe before sleep
server::subscribe(d);
sleep_for_seconds(random_seconds); //sleeps for some random time in seconds.
std::cout << *d << std::endl;
}
}
想象一下server::update
和client::subcribe_sleep_print
正在不同的线程上运行。这不安全,因为shared_ptr
服务器写入时可能会被破坏?有没有办法在没有用户(我)定义的原子或互斥体的情况下实现这一点?我不介意它是否在后台使用,只要我自己不添加它们(原子/互斥),因为我知道共享指针已经使用原子计数器。
编辑:我没有在程序中使用 double,我使用的是线程安全对象:) 因此操作 += 可以假定为线程安全。对不起。
不,它不是线程安全的。您面临着竞争条件,在您检查过期之后,指针可能会过期。在这种情况下,您现在已经取消引用了
nullptr
.因此,正确的方法是显式地使用
std::weak_ptr<T>::lock()
尝试获取关联的共享指针(这也是expired()
内部执行的操作),并且仅当获得有效的指针时,您才可以进行读或写访问。如果您没有获得有效的共享指针,则将其视为
expired()
返回 false。我确信你的顺序错了。您原本打算先更新,然后清除
nullptr
更新回调所产生的内容。