C++ volatile关键字总结

volatile关键字有什么作用?

  1. 保持内存可见性
  2. 禁止重排序
  3. 防止编译器优化

什么叫内存可见性?

当一个数据(或者多线程中的共享数据)发生改变时,这个改变能够立刻被自己(或者其他线程)感知到。

自己的数据,为什么还说立刻被自己感知到呢?因为当一个经过初始化的数据立即被使用时,编译器会进行优化,直接从寄存器中将这个数据取出,而不是从内存中取。因为是从寄存器直接取出的数据,因此内存中的数据我并不知道是否发生改变(虽然单线程下这个数据并不会发生改变),这就是内存不可见

而对于多线程的共享数据就好理解了,这里假设有线程A和线程B,共享数据 s=10
当线程A访问一个 s 时会先将数据保存到寄存中,然后进行下面的操作,可是如果将 s 加入到寄存器后线程B将内存中的数据改为了20,然而线程A并不知道,线程A会继续从寄存器中取出 s 进行操作,这就是内存不可见。

volatile 就可以用来解决这个问题,无论何时,当访问一个数据的时候,都必须从内存中重新获取数据而不能直接用保存在寄存器中的数据。这样就保证了内存的可见性。

什么是禁止重排序?

重排序是一种编译器优化代码的手段,举例说明:

Singleton* instance = new Singleton();

上面代码中,我们试图为一个类对象指针申请一块儿空间,如果没有优化,编译器会分三步做:

1)分配一块儿内存
2)在此内存上调用构造函数进行初始化操作
3)将指针指向该内存块

而经过编译器优化,编译器同样会分三步,但是顺序有所不同

1)分配一块儿内存
2)将指针指向该内存块
3)在此内存上调用构造函数进行初始化操作

这就是重排序,当在多线程条件下可能会出现问题。这正是懒汉方式的单例模式下需要考虑的问题:下面是懒汉方式单例模式的代码实现:
为了防止锁冲突影响效率,使用了双重判断,但是与此同时带来的问题是:可能会访问未被初始化的空间,就是重排序导致的。

假设线程A和线程B,线程A第一次调用GetInstance() 此时会加锁然后进入 #4行,上面讲过分三步进行,假设这是经过编译器优化的,并且执行到第二步,时间片轮转到线程B。线程B同样获取这个单例对象,判断instance 并不为空(因为线程A中执行了第二步),就直接使用了这个对象,然而这个对象还没有被初始化(线程A没有执行第三步),就出问题了。

解决的方案就是将instance 用volatile关键字修饰,禁止重排序。

class Singleton {
    public:
        static Singleton* GetInstance() {
        	//二重判断
            if (instance == nullptr) { 			// #1
                pthread_mutex_lock(&_mutex); 	// #2
                if (instance == nullptr) { 		// #3
                    printf("第一次实例化~~\n");
                    instance = new Singleton();	// #4
                }
                pthread_mutex_unlock(&_mutex);	// #5
            }
            return instance;
        }
    private:
        Singleton(){
            pthread_mutex_init(&_mutex, NULL);
            printf("Singeton~~\n");
        }
        //volatile 防止编译器优化,造成调用未初始化的对象
        static Singleton* volatile instance;
        static pthread_mutex_t _mutex;
};
Singleton* volatile Singleton::instance = nullptr;
pthread_mutex_t Singleton::_mutex;

什么是编译器优化?

volatile 的上面两点作用,其实都使用到了编译器优化。
编译器的优化为的是提高代码执行效率,避免没有必要的代码步骤,通常这是好的。
但是有时候我们也并不希望编译器替我们优化,最明显的就是调试代码的时候,生成的debug版本就是没有经过编译器优化的。volatile 同样也可以起到帮助我们禁止编译器优化的作用。

发布了146 篇原创文章 · 获赞 82 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_40860852/article/details/103202530