【问题标题】:volatile keyword and RAII idiom (C++)volatile 关键字和 RAII 习语 (C++)
【发布时间】:2015-02-02 22:35:41
【问题描述】:

假设有一个类来控制对与此类似的(关键)代码块的并发访问:

class RAIIObj : public boost::noncopyable {
public:
    explicit RAIIObj( LockObj& Obj ) : LkObj( Obj ) { Obj.Acquire(); }
    ~RAIIObj() { try { Obj.Release(); } catch (...) {} }
private:
    LockObj& LkObj;
};

在使用这样的代码时,是否需要使用 volatile 关键字来排序 不想看到代码被优化掉?

例如,我必须写吗

ALockingObj LockObj;

void AFunc() {
    RAIIObj LKGuard( LockObj );

    // do some MT stuff
}

ALockingObj LockObj;

void AFunc() {
    volatile RAIIObj LKGuard( LockObj );

    // do some MT stuff
}

为了确保 LKGuard 始终存在?

由于 LKGuard 是一个局部变量,在 如果我不使用 volatile 关键字,可以优化掉这个函数吗?

谢谢

【问题讨论】:

  • 我认为只有一两个实例可以优化构造函数/析构函数对,例如RVO。否则我不会担心的。
  • 感谢您的澄清。问候

标签: c++ volatile raii


【解决方案1】:

不,您不需要将其声明为 volatile。编译器可以看到实例化 lkobj 做了一大堆无法优化的事情(与 int lkobj; 显然什么都不做相反)

【讨论】:

  • 感谢您的宝贵时间。问候。
【解决方案2】:

虽然 pm100 提供的答案就标准而言确实是正确的,但我发现 GCC 4.9 可以优化 RAII 类型(优化标志:-Os -flto)。这是优化器丢弃的代码:

class MutexLocker
{
    chibios_rt::Mutex& mutex_;
public:
    MutexLocker(chibios_rt::Mutex& m) : mutex_(m)
    {
        mutex_.lock();
    }
    ~MutexLocker()
    {
        mutex_.unlock();
    }
};

使类型为 volatile 解决了这个问题:

namespace impl_
{
    class MutexLockerImpl
    {
        chibios_rt::Mutex& mutex_;
    public:
        MutexLockerImpl(chibios_rt::Mutex& m) : mutex_(m)
        {
            mutex_.lock();
        }
        ~MutexLockerImpl()
        {
            mutex_.unlock();
        }
    };
}
using MutexLocker = volatile impl_::MutexLockerImpl;

因此,尽管标准不要求这样做,但我建议明确声明 RAII 类型 volatile 以考虑积极优化。

【讨论】:

  • 编译器必须确定mutex_.lock() 和相关的解锁对其余代码没有影响(即代码在有或没有锁的情况下运行相同)。如果这实际上不是真的,那么这意味着 lock() 函数没有正确实现,需要修复 - 用 volatile 覆盖这个实例中的错误不是一个好的解决方案,同样的错误可能会出现在您的其他地方没意识到。
  • 也许您可以使用MCVE 发布一个新问题
  • 我倾向于认为这是一个 GCC 错误。这并不奇怪,因为我使用的版本 4.9.3 (arm-none-eabi) 实际上非常不稳定。 lock() 方法的实现可以在这里找到:github.com/ChibiOS/ChibiOS/blob/stable_3.0.x/os/various/…;这只是一个代理:github.com/ChibiOS/ChibiOS/blob/stable_3.0.x/os/rt/src/…。 (是的,这是一个嵌入式系统)。我知道 MCVE 在这里会有所帮助,但是为嵌入式应用程序提供一个有点复杂。
  • 在那个锁实现中似乎没有任何内存栅栏,也许应该添加一个编译器特定的栅栏
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多