【问题标题】:Synchronizing access to a return value同步访问返回值
【发布时间】:2011-03-13 02:46:22
【问题描述】:

考虑以下 C++ 成员函数:

 size_t size() const
 {
    boost::lock_guard<boost::mutex> lock(m_mutex);
    return m_size;
 }

这里的目的不是同步对私有成员变量m_size的访问,而是确保调用者接收到一个有效的m_size值。目的是防止函数在其他线程正在修改m_size 的同时返回m_size

但是调用这个函数有没有潜在的竞争条件?我不确定这里的 RAII 样式锁是否足以防止竞争条件。假设在函数的返回值被压入堆栈之前调用了锁的析构函数?

我是否需要执行以下操作来保证线程安全?

 size_t size() const
 {
    size_t ret;

    {
      boost::lock_guard<boost::mutex> lock(m_mutex);
      ret = m_size;
    }

    return ret;
 }

【问题讨论】:

  • 我不认为你的锁真的有任何作用。只要可以在单个原子操作中完整读取m_size,您就会得到一个有效值。
  • 这实际上并不能保证。但是使用 C++0x 附带的std::atomic 可以确保这一点没有锁定。
  • @Mike:锁也是一个内存屏障。这是同步处理器缓存等所需要的。

标签: c++ multithreading boost-thread thread-safety


【解决方案1】:

您的两个示例构造都可以满足您的需求。标准中的以下信息支持您正在寻找的行为(即使在您的第一个示例中):

12.4/10 析构函数:

当创建对象的块退出时,对具有自动存储持续时间 (3.7.2) 的构造对象隐式调用析构函数。

还有,6.6/2 条跳转语句(其中return 是一个):

在退出作用域时(无论如何完成),对于在该作用域中声明的所有具有自动存储持续时间 (3.7.2) 的构造对象(命名对象或临时对象)调用析构函数 (12.4),顺序与他们的宣言。转移出循环、转移出块或返回具有自动存储持续时间的初始化变量涉及销毁具有自动存储持续时间的变量,这些变量在转移点的范围内但不在转移点的范围内。

所以在return 处,lock 变量在作用域内,因此没有调用 dtor。一旦 return 被执行,lock 变量的 dtor 就会被调用(从而释放锁)。

【讨论】:

    【解决方案2】:

    您的第一个变体是安全的,但是您不能依赖此返回值在任何时间段内保持一致。我的意思是,例如,不要在 for 循环中使用该返回值来迭代每个元素,因为实际大小可能会在返回后立即改变。

    基本上你可以这样想:需要一个返回值的副本,否则会调用析构函数,因此可能会破坏返回值在返回之前的任何内容。

    在 return 语句之后调用析构函数。 拿这个等价的例子:

    #include <assert.h>
    
    class A
    {
    public:
        ~A()
        {
            x = 10;
        }
        int x;
    };
    
    int test()
    {
        A a;
        a.x = 5;
        return a.x;
    }
    
    int main(int argc, char* argv[])
    {
        int x = test();
        assert(x == 5);
        return 0;
    }
    

    【讨论】:

    • 经过思考,我发现这是该行为唯一可行的方法。每个return expr; 都将expr 的值隐式复制到一个临时文件中,并且范围内的任何对象都可以在expr 中引用,因此它们必须在复制时仍然存在。 (优化当然可以删除副本,但行为必须仍然“好像”它在那里。)
    【解决方案3】:

    您的初始代码很好 - 将在存储返回值后调用析构函数。这就是 RAII 运作的原则!

    【讨论】:

    • 你有这方面的资料吗?
    猜你喜欢
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 2022-11-19
    • 2019-04-06
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 2022-01-24
    相关资源
    最近更新 更多