我们需要在关键部分创建变量的副本吗?

问题描述 投票:0回答:2
void Animal::notifyEatingInitiated() {
    log.debug(TAG, "notifyEatingInitiated called");
     
    std::lock_guard<std::mutex> lock(m_mutex);
    auto observers = m_observers;
     
    for (const auto& observer : observers) {
        observer->notifyEatingInitiated();
    }
}

我正在学习 C++ 教程,在这里我看到在关键部分中我们正在创建实例变量的副本

m_observers
,然后对其进行迭代。

是否需要创建一个副本

m_observers

临界区不是会锁定当前作用域(这里

m_observers
)之外的变量来进行修改吗?

c++ multithreading thread-safety
2个回答
0
投票

一般情况下不需要复印

从线程安全的角度来看这是没有必要的。 有以下几种可能:

  1. m_observers
    到处都有
    std::mutex
    妥善保护,因此简单地循环
    m_observers
  2. 也是同样安全的
  3. m_observers
    在其他位置没有被
    std::mutex
    正确保护,在这种情况下,在
    auto observers = m_observers;
    中调用复制构造函数无论如何都是数据争用

无论哪种情况,为了线程安全的目的而复制

m_observers
都是没有意义的。

从性能角度来看,复制可能很有用

这样写可能有意义:

auto observers = [this] {
    std::lock_guard<std::mutex> lock(m_mutex);
    return m_observers;
}(); // immediately invoked lambda expression (IILE)

for (const auto& observer : observers) {
    observer->notifyEatingInitiated();
}

如果

notifyEatingInitiated()
需要很长时间,并且复制
m_observers
很便宜,那么这将是一个重大改进,因为它限制了在关键部分花费的时间。 您的示例甚至没有尝试获得复制的好处
observers
,因此教程的作者更有可能误解了该主题,或者犯了一个错误。

但是如果
notifyEatingInitiated()
修改了
m_observers
呢?

正如评论者@HolyBlackCat 所指出的,

notifyEatingInitiated()
可能会修改
m_observers
。 在这种情况下,有必要复制
m_observers
以避免在迭代过程中修改容器。

虽然这会令人惊讶且容易出现错误的设计,但有必要像作者在您的示例中所做的那样完全编写代码。


0
投票

在您的具体情况下,整个代码已损坏。每个线程通过复制一些不相关的观察者来创建并通知它们,而

m_observers
永远不会被通知。

void Animal::notifyEatingInitiated() {
         log.debug(TAG, "notifyEatingInitiated called");
     
         std::lock_guard<std::mutex> lock(m_mutex); 
         auto observers = m_observers; //observers at this point are copy of m_observers not refference to m_observers
     
         for (const auto& observer : observers) {
             observer->notifyEatingInitiated();
         }
     } 

这种复制的使用是无关紧要的,并且完全杀死了代码。复制比构建便宜,因此应该使用,因为在适当的地方速度更快。对象的副本绝不是初始对象的别名,它是全新的对象。了解浅复制和深复制。如上所述,线程安全得不到保证。为了线程安全,始终使用保护和公开方法进行包装,例如

safe_notify_all()
,其中
m_mutex
m_observers
都是包装器的私有成员。

© www.soinside.com 2019 - 2024. All rights reserved.