【并发编程实战】并发的编程引发的三个问题--可见性/原子性/顺序性

前言

    硬件和软件的发展都是相互的,硬件的发展,多核CPU,缓存,进程,线程,我们享受CPU带来的高性能的同时,必定同时也伴随着风险。为了解决这些,则出现了一些理论和实践

问题

问题一  缓存导致的可见性问题

   可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到,我们称为可见性。

   单核时代:所有的线程都是在一颗 CPU 上执行,CPU 缓存与内存的数据一致性容易解决。因为所有线程都是操作同一个 CPU 的缓存,一个线程对缓存的写,对另外一个线程来说一定是可见的。

    多核时代:每颗 CPU 都有自己的缓存,这时 CPU 缓存与内存的数据一致性就没那么容易解决了,当多个线程在不同的 CPU 上执行时,这些线程操作的是不同的 CPU 缓存。

    如下图  多核的变量的变更两个线程之间时不可见的,都是独立的缓存。

      

问题二  线程切换带来的原子性问题

原子性:我们把一个或者多个操作在 CPU 执行的过程中不被中断的特性称为原子性。

 线程切换:指的是操作系统在多任务环境下,由于需要让不同的线程轮流执行,而对当前正在运行的线程进行暂停,并切换到另一个线程上运行的过程。在多线程环境中,操作系统会通过调度算法来决定哪个线程可以运行,并在必要时进行线程切换,以实现多个线程并发执行的目的。

线程切换通常涉及以下几个步骤:

  1. 保存当前线程状态: 当操作系统决定要切换到另一个线程时,首先会保存当前线程的上下文信息,包括程序计数器、寄存器状态、堆栈指针等,以便稍后能够恢复到该线程的执行状态。

  2. 选择下一个要运行的线程: 在多任务环境下,操作系统需要决定下一个要运行的线程是哪一个。这通常由调度算法来决定,调度算法的选择会影响到线程的调度策略,比如先来先服务、最短作业优先、时间片轮转等。

  3. 恢复下一个线程的状态: 一旦操作系统确定了下一个要运行的线程,它会从该线程保存的上下文信息中恢复线程的状态,包括程序计数器、寄存器状态、堆栈指针等,然后将处理器的控制权转移到该线程上,使其开始执行。

线程切换的频繁发生会带来一定的性能开销,因为切换过程涉及到保存和恢复线程状态的操作,以及调度算法的开销。因此,在设计多线程应用程序时,需要注意减少线程切换的次数,以提高程序的性能和效率。

实例分析:count += 1

问题三  编译优化带来的有序性问题

编译程序的有序性问题通常指的是编译器对代码的优化可能导致的指令执行顺序与源代码中的顺序不一致的情况。在多核处理器和乱序执行的情况下,这种优化可能会引发一些意想不到的问题,尤其是在并发编程中。

具体来说,编译器在进行代码优化时可能会对指令进行重新排序,以提高程序的性能。这种重新排序可能导致源代码中的指令顺序与实际执行的指令顺序不一致,从而引发一些问题,比如:

  1. 数据竞争: 如果编译器将某些操作提前到了原本不应该执行的位置,可能会导致多个线程之间的数据竞争问题,从而产生不确定的结果。

  2. 内存一致性问题: 在多核处理器上,由于缓存和乱序执行的影响,可能会导致内存访问的一致性问题,即不同线程或核心对同一内存位置的读写顺序不一致,从而导致错误的结果。

  3. 指令重排导致的逻辑错误: 如果编译器进行了过度的指令重排,可能会破坏程序的逻辑顺序,导致程序行为与预期不符。

为了解决编译程序的有序性问题,可以采取以下几种方法:

  1. 使用内存屏障(Memory Barriers): 内存屏障是一种指令,用于确保某些操作在其他操作之前或之后执行,从而保证了内存访问的顺序性和一致性。

  2. 使用同步原语: 使用锁、信号量等同步原语可以保证临界区内的指令按照顺序执行,从而避免了由于指令重排导致的逻辑错误和数据竞争问题。

  3. 禁用特定的编译器优化: 对于涉及到并发编程的代码,可以通过编译器提供的编译选项或者特定的编译器指令来禁用特定的优化,以确保编译程序的有序性。

  4. 使用原子操作: 原子操作可以确保某些操作的原子性和顺序性,从而避免了编译程序的有序性问题。

public class Singleton {
  static Singleton instance;
  static Singleton getInstance(){
    if (instance == null) {
      synchronized(Singleton.class) {
        if (instance == null)
          instance = new Singleton();
        }
    }
    return instance;
  }
}
  1. getInstance() 方法并不完美。问题出在哪里呢?出在 new 操作上,我们以为的 new 操作应该是:分配一块内存 M;在内存 M 上初始化 Singleton 对象;然后 M 的地址赋值给 instance 变量。但是实际上优化后的执行路径却是这样的:分配一块内存 M;将 M 的地址赋值给 instance 变量;最后在内存 M 上初始化 Singleton 对象。优化后会导致什么问题呢?我们假设线程 A 先执行 getInstance() 方法,当执行完指令 2 时恰好发生了线程切换,切换到了线程 B 上;如果此时线程 B 也执行 getInstance() 方法,那么线程 B 在执行第一个判断时会发现 instance != null ,所以直接返回 instance,而此时的 instance 是没有初始化过的,如果我们这个时候访问 instance 的成员变量就可能触发空指针异常。

总的来说,编译程序的有序性问题在并发编程中是一个重要的考虑因素。通过合适的编程技术和编译器选项,可以有效地解决这些问题,确保程序的正确性和性能。

总结

在介绍可见性、原子性、有序性的时候,特意提到缓存导致的可见性问题线程切换带来的原子性问题编译优化带来的有序性问题,其实缓存、线程、编译优化的目的和我们写并发程序的目的是相同的,都是提高程序性能。但是技术在解决一个问题的同时,必然会带来另外一个问题,所以在采用一项技术的同时,一定要清楚它带来的问题是什么,以及如何规避

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/582494.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最佳WordPress外贸主题推荐(2024)

WordPress是一个非常受欢迎的建站平台,它具有易用性,并提供了许多功能强大的主题和插件。如果你计划建立一个外贸独立站商城,选择一个适合的WordPress外贸主题至关重要。以下是一些外贸主题应具备的特点: 1. 欧美风格&#xff1a…

python代码实现kmeans对鸢尾花聚类

导入第三方库和模型 from sklearn import datasets import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans2、创建画图函数 def draw_result(train_x, labels, cents, title):n_clusters np.unique(labels).shape[0]#获取类别个数color …

美富特 | 邀您参加2024全国水科技大会暨技术装备成果展览会

王涛 四川美源环能科技有限公司 技术总监 报告题目:绿色智慧水岛如何助力工业园区污水及再生水资源化利用降碳增效 拥有十余年的环保行业从业经验,对各类前沿物化、生化及膜技术均有丰富的研发、设计及应用经验,先后参与多项重点核心技术…

spring cloud eureka 初始化报错(A bean with that name has already been defined)

报错内容 The bean ‘eurekaRegistration’, defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration E u r e k a C l i e n t C o n f i g u r a t i o n . c l a s s ] , c o u l d n o t b e r e g i s t e r e d . A …

Unity 数字字符串逗号千分位

使用InputField时处理输入的数字型字符串千分位自动添加逗号,且自动保留两位有效数字 输入:123 输出:123.00 输入:12345 输出:12,345.00 代码非常简单 using UnityEngine; using TMPro;public class …

ssm088基于JAVA的汽车售票网站abo+vue

汽车售票网站的设计与实现 摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对汽车售票信息管理混乱,出错率…

C++——string类的使用

1、string的构造 在 c plus plus 这个网站上可以查到相关的信息, (1)是无参构造函数(也是默认构造),就是一个空字符串 (2)是一个拷贝构造,传入一个参数构造字符串 (3)是一个有参构造,参数有点复杂,他有一个字符串,在…

强化SSH服务安全的最佳实践

SSH(Secure Shell)作为一种广泛应用于Linux和其他类Unix系统中的强大工具,为管理员提供了安全的远程登录和命令执行功能。在现今高度互联的网络环境中,确保SSH服务的安全性显得尤为重要。本文将详细阐述一系列SSH服务的最佳实践&a…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (3) :3DCNN

稳态视觉诱发电位分类学习系列:3DCNN 0. 引言1. 主要贡献2. 提出的方法2.1 解码主要步骤2.2 网络具体结构2.3 迁移策略 3. 结果和讨论3.1 数据集1上的结果3.2 数据集2上的结果3.3 零填充 4. 总结欢迎来稿 论文地址:https://www.sciencedirect.com/science/article/a…

优秀博士学位论文分享:动态三维场景理解与重建

优秀博士学位论文代表了各学科领域博士研究生研究成果的最高水平,本公众号近期将推出“优秀博士学位论文分享”系列文章,对人工智能领域2023年优秀博士学位论文进行介绍和分享,方便广大读者了解人工智能领域最前沿的研究进展。 “博士学位论…

基于java+springboot+vue实现的在线考试系统(文末源码+Lw)204

摘 要 使用旧方法对在线考试系统的信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在在线考试系统的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。这次开发的在线考试…

OpenAI发布GPT-4.0使用指南

大家好,ChatGPT 自诞生以来,凭借划时代的创新,被无数人一举送上生成式 AI 的神坛。在使用时,总是期望它能准确理解我们的意图,却时常发现其回答或创作并非百分之百贴合期待。这种落差可能源于我们对于模型性能的过高期…

百万人都在求的网络安全学习路线,渗透漏洞防御总结(附图)

前言 不折腾的网络安全,和咸鱼有什么区别 目录 二、 前言三 、同源策略 3.1 什么是同源策略 3.2 为什么需要同源策略四 、XSS 4.1 概览 4.2 介绍 4.3 防御五 、CSRF 5.1 概览 5.2 介绍 5.3 防御六、 SQL 注入七 、流量劫持 7.1 DNS 劫持 7.2 HTTP 劫持…

企业微信hook接口协议,ipad协议http,发送小程序

发送小程序 参数名必选类型说明uuid是String每个实例的唯一标识,根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"543ed7f3-6ec1-4db8339a140f7","send_userid":788130255…

「生存即赚」链接现实与游戏,打造3T平台生态

当前,在线角色扮演游戏(RPG)在区块链游戏市场中正迅速崛起,成为新宠。随着区块链技术的不断进步,众多游戏开发者纷纷将其游戏项目引入区块链领域,以利用这一新兴技术实现商业价值的最大化。在这一趋势中&am…

Android如何使用XML自定义属性

1、定义 在res/values文件下定义一个attrs.xml文件,代码如下: 2、使用 在布局中使用, 示例代码如下: 3、获取 最终来到这里:

异常处理Exception(二)

文章目录 1、自定义异常类1、定义消息类2、自定义异常类 2、调用3、测试总结 ABAP预定义的异常类在某些时候并不能精确地描述异常,此时就需要自定义异常类。 1、自定义异常类 1、定义消息类 2、自定义异常类 在Local Types中自定义异常类,当异常触发时…

开箱即用的使用体验!Alibaba Cloud Linux 的演进之旅

随着云计算的发展,越来越多的云上用户对操作系统提出了新的诉求。在 2023 龙蜥操作系统大会阿里云分论坛上,阿里云操作系统团队贾正华分享了 Alibaba Cloud Linux(以下简称“Alinux”)的发展历程及未来展望,介绍了 Ali…

unittest_parameterized批量测试测试用例

import unittest from parameterized import parameterizeddef add(x, y):return xy"""问题:如果有三组数据需要测试?[(1,1,2), (1,2,3), (0,3,3)] """def get_data():return [(1, 2, 3), (3, 0, 3), (2, 1, 3)]# 定义测试…

第3篇:创建Nios II工程之Hello_World<二>

Q:上一期介绍完基本设计流程和实验原理,接着我们完成系统硬件设计部分,包括Platform Designer系统及Quartus工程。 A:依次搜索并添加Nios II Processor、JTAG UART、On-Chip Memory和System ID IP组件,连接各组件并As…
最新文章