C++中volatile关键字及常见的误解总结

C++中volatile关键字及常见的误解总结

什么是volatile关键字

volatile 是一个类型修饰符,用于告诉编译器,该变量可能在程序执行阶段被不由程序本身产生的修改。

通俗点讲,当我们定义一个变量时,系统会在内存中为其分配一块内存区域,我们通过对这些内存的读写来操作这些变量。但是在复杂的多线程并发编程中,可能出现另外一个线程或者硬件设备修改了这块内存区域,从而导致了程序错误。所以这时我们需要告诉编译器,这个变量可能会被意外修改,编译器就不会把这个变量缓存到寄存器中,注意到每次访问都要从内存中读取,从而减小了出错的机会。

volatile的使用

又由于volatile本身只是告诉编译器,变量有可能产生变化,并不会强制刷新,所以在多线程并发编程中,volatile关键字是不够保险的。

使用方法:

volatile int num = 0;
volatile char ch = 'a';
volatile double pi = 3.14159;

volatile的常见误解

误解1:volatile变量是线程安全的

volatile关键字并不能保证线程安全。volatile并不能保证原子性(线程的基本操作单位,具有不可分割性)。如果涉及到需要确保原子性的操作,还必须依靠更强的多线程并发编程机制,如互斥锁、自旋锁、条件变量等。

例如:

volatile int num = 0;
for(int i = 0; i < 10000; ++i){
    ++num;
}

如果两个线程同时执行这段代码,num的值是不确定的,因为volatile并不能保证原子性。

误解2:volatile变量不写入cpu缓存,每次读/写都会从内存中读取/写入

这个误解有一部分是正确的。volatile变量不会缓存,但不代表每次都会从内存中读取/写入,CPU有自己多级缓存,volatile只能保证在缓存失效的时候从内存中取值,具体在什么时候失效并不是我们可以控制/预知的,所以在使用volatile变量的时候还是要小心谨慎,避免因为缓存失效而导致的问题。

例如:

volatile int num = 0;
for(int i = 0; i < 10000; ++i){
    num += i;
}

这段代码在多次循环后,由于计算次数增加,可能会被缓存,所以不会每次都从内存中取值。

示例说明

以下是一个示例程序,该程序利用volatile关键字保证了信号量变量在多线程应用中正确的使用。

#include <iostream>
#include <thread>

using namespace std;

volatile int sem = 1;

void producer() {
    for (int i = 0; i < 1000; ++i) {
        while (sem == 0) {
            // wait until sem == 1
        }
        sem = 0;
        cout << "Producer produces " << i << endl;
    }
}

void consumer() {
    for (int i = 0; i < 1000; i++) {
        while (sem == 1) {
            // wait until sem == 0
        }
        sem = 1;
        cout << "Consumer consumes " << i << endl;
    }
}

int main() {
    thread t1(producer);
    thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}

在这个程序中,我们定义了一个信号量变量sem,并使用while循环来保证信号量的正确性。由于while循环的判断条件依赖于sem的值,在多线程编程中,如果没有使用volatile关键字,就可能会出现由于编译器优化而导致的信号量错误的情况。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++中volatile关键字及常见的误解总结 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • JS循环遍历JSON数据的方法

    以下是详细的讲解”JS循环遍历JSON数据的方法”的完整攻略: 1. 解析JSON数据 在JS中,可以通过JSON.parse将字符串转换为JSON对象,也可以直接将JSON数据引入JS文件中,得到一个JSON对象。解析成功后,我们即可对JSON数据进行操作。 1.1 解析字符串为JSON对象 const jsonData = ‘{"name&qu…

    C 2023年5月23日
    00
  • 详解C/C++中低耦合代码的设计实现

    详解C/C++中低耦合代码的设计实现 在C/C++开发过程中,低耦合的代码设计和实现可以提高代码的可读性、可维护性和可重用性,更加适合大型项目的开发。下面我们将详细讲解如何实现低耦合的代码设计。 1. 引入头文件的精简化 在编写C/C++代码的时候,我们会引入许多头文件,这些头文件中可能包含了许多不必要的定义和声明。这些不必要的定义和声明会增加代码的耦合度。…

    C 2023年5月30日
    00
  • Golang实现解析JSON的三种方法总结

    当我们需要解析JSON格式数据时,Golang提供了三种方法:- 使用encoding/json包- 使用第三方库github.com/tidwall/gjson- 使用第三方库github.com/json-iterator/go 1. encoding/json包解析JSON数据 在Golang中,我们可以使用标准库中的encoding/json包来解析…

    C 2023年5月23日
    00
  • C++简单又轻松建立链式二叉树流程

    下面是关于“C++简单又轻松建立链式二叉树”的攻略。 什么是链式二叉树 链式二叉树是一种常见的树形结构,它由多个节点构成,每个节点可以有左子树、右子树和父节点。链式二叉树的特点是不需要连续的内存空间,因此它的插入和删除操作非常方便。 如何建立链式二叉树 在C++中,我们可以使用结构体表示每个二叉树节点,具体实现方式如下: struct TreeNode { …

    C 2023年5月30日
    00
  • C++实现停车场管理系统

    C++实现停车场管理系统的完整攻略 目录 简介 功能需求 设计思路 代码实现 示例说明 总结 1. 简介 停车场管理系统是一种常见的用于管理停车场的软件系统,通常包括车辆进入、出场、停车位置管理等多个功能。本文将介绍如何使用C++语言实现一个简单的停车场管理系统。 2. 功能需求 本次实验中,我们将实现以下功能: 停车:记录车辆入场时间和车牌号,并将车辆信息…

    C 2023年5月23日
    00
  • C++超详细讲解引用和指针

    C++超详细讲解引用和指针 什么是指针和引用 在C++中,指针和引用是两种重要的数据类型。 指针是一个变量,存储一块内存的地址;而引用则是一种别名,可以让我们通过一个名称来访问另一个变量或对象。 指针的声明和使用 指针的声明需要指定指针所指向的类型,并使用星号(*)进行标识。例如,声明一个指向整数类型的指针如下: int* ptr; 指针的使用需要注意以下几…

    C 2023年5月22日
    00
  • C语言 详解如何删除有序数组中的重复项

    C语言详解如何删除有序数组中的重复项 在C语言中,要删除有序数组中的重复项,可以使用双指针法来实现。具体步骤如下: 定义两个指针p和q,分别指向数组的第一个元素。 使用循环遍历数组,当q指针所指向的元素与p指针所指向的元素相同时,q指针向后移动一位,即跳过该重复项。 当q指针所指向的元素与p指针所指向的元素不同时,将q指针所指向的元素赋值给p指针的下一个位置…

    C 2023年5月23日
    00
  • C++实现控制台版扫雷程序

    下面是关于C++实现控制台版扫雷程序的完整攻略: 步骤一:了解游戏规则 在开发扫雷程序之前,我们需要先了解游戏规则。扫雷游戏是一款单人益智游戏,游戏棋盘被分为许多方块,有些方块里面有地雷,有些方块里面没有地雷。游戏的目标是找出没有地雷的方块,并标记出有地雷的方块。 步骤二:设计游戏窗口 在C++中,我们可以使用控制台窗口作为游戏窗口。通过调用Windows …

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部