在有关多线程编程的话题中,数据争用(data race) 和竞态条件(race condition)是两个经常被提及的名词,它们两个有着相似的名字,也是我们在并行编程中极力避免出现的。但在处理实际问题时,我们应该能明确区分它们两个。

1.数据争用(data race)

定义:①多个线程对于同一个变量、②同时地、③进行读/写操作的现象并且④至少有一个线程进行写操作。(也就是说,如果所有线程都是只进行读操作,那么将不构成数据争用)
后果:如果发生了数据争用,读取该变量时得到的值将变得不可知,使得该多线程程序的运行结果将完全不可预测,可能直接崩溃。
如何防止:对于有可能被多个线程同时访问的变量使用排他访问控制,具体方法包括使用mutex(互斥量)和monitor(监视器),或者使用atomic变量。

2.竞态条件(race condition)

相对于数据争用(data race),竞态条件(race condition)指的是更加高层次的更加复杂的现象,一般需要在设计并行程序时进行细致入微的分析,才能确定。(也就是隐藏得更深)
定义:受各线程上代码执行的顺序和时机的影响,程序的运行结果产生(预料之外)的变化。
后果:如果存在竞态条件(race condition),多次运行程序对于同一个输入将会有不同的结果,但结果并非完全不可预测,它将由输入数据和各线程的执行顺序共同决定。
如何预防:竞态条件产生的原因很多是对于同一个资源的一系列连续操作并不是原子性的,也就是说有可能在执行的中途被其他线程抢占,同时这个“其他线程”刚好也要访问这个资源。解决方法通常是:将这一系列操作作为一个critical section(临界区)。

3.代码示例

下面以C++实现的一个银行存款转账操作为例,说明数据争用(data race) 和竞态条件(race condition)的区别。

  • 该系统的不変性条件:存款余额≥0,不允许借款。

3.1.数据争用的例子

int my_account = 0;      //我的账户余额
int your_account = 100;  //你的账户余额// 转账操作: 存在数据争用(data race)!
bool racy_transfer(int& src, int& dst, int m)
{if (m <= src) {  //操作结果不可预测src -= m;      //操作结果不可预测dst += m;      //操作结果不可预测return true;} else {return false;}
}// 将下面两个函数在两个线程分别运行
racy_transfer(your_account, my_account, 50);
racy_transfer(your_account, my_account, 80);

运行上面的的代码后,不光我们双方账号的余额不可预测,甚至整个系统会发生什么事情都无法保证。

3.2.竞态条件的例子

#include <atomic>
std::atomic<int> my_account = 0; //我的账户余额
std::atomic<int> your_account = 100;  //你的账户余额// 汇款操作:没有数据争用(data race),但存在竞态条件(race condition)!
bool unsafe_transfer(std::atomic<int>& src, std::atomic<int>& dst, int m)
{if (m <= src) {// ★在这个时候(m <= src)是否仍然成立?src -= m;dst += m;return true;} else {return false;}
}//将下面两个函数在两个线程分别运行
unsafe_transfer(your_account, my_account, 50);//[A]
unsafe_transfer(your_account, my_account, 80);//[B]

上面代码中所标注的就是竞态条件,也就是这时候m > src是完全有可能的。考虑以下三种情况:

  • [A]执行结束后,your_account == my_account == 50[B]再开始执行,然而条件不满足,转账失败;
  • [B]执行结束后,your_account == 20 && my_account == 80[A]再开始执行,然而条件不满足,转账失败;
  • [A][B]交错执行,而且都进入了if块之内,最终结果变成your_account == -30 && my_account == 130,程序虽然能正常退出,但显然违反了不变性条件——存款余额≥0

对应于C++std::atomic<int>、在Javajava.util.concurrent.atomic.AtomicInteger类(或者volatile修饰的变量)。

3.3.解决办法

#include <mutex>
int my_account = 0;//我的账户余额
int your_account = 100; //你的账户余额
std::mutex txn_guard;//安全的转账操作
bool safe_transfer(int& src, int& dst, int m)
{//声明临界区开始std::lock_guard<std::mutex> lk(txn_guard);if (m <= src) {src -= m;dst += m;return true;} else {return false;}
}  //临界区结束//将下面两个函数在两个线程分别运行
safe_transfer(your_account, my_account, 50);  // [A]
safe_transfer(your_account, my_account, 80);  // [B]

这样程序只会产生以下两种结果:

  • [A]执行结束后,your_account == my_account == 50[B]再开始执行,然而条件不满足,转账失败:
  • [B]执行结束后,your_account == 20 && my_account == 80[A]再开始执行,然而条件不满足,转账失败;

而不会出现[A][B]交错执行的情况,从而使数据始终符合系统规定的不变形条件。对应于C++std::mutexstd::lock_guard,在Javamonitor(通常不用显式声明)+synchronized的组合。

别混淆数据争用(data race) 和竞态条件(race condition)相关推荐

  1. 数据争用(data race) 和竞态条件(race condition)

    在有关多线程编程的话题中,数据争用(data race) 和竞态条件(race condition)是两个经常被提及的名词,它们两个有着相似的名字,也是我们在并行编程中极力避免出现的.但在处理实际问题 ...

  2. python 很高兴问题_Python 3.7曾有一个很老的GIL竞态条件(race condition),我是这么解决的...

    Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 作者:Victor Stinner 作为Python最关键的组成部分之一:GIL(全局解释器锁),我花了4 ...

  3. eclipse运行go test_在 Go 中发现竞态条件 (Race Conditions)

    当我意识到我一直在处理和解决的问题有一个专有名词描述的时候,我总会觉得这事十分有趣.这次出现这种情况的是竞争条件(Race Conditions).当你处理多个 routine 共享某类资源的时候,不 ...

  4. 竞态条件(race condition)

    在学习多线程的过程中,因为是非科班学生,操作系统的东西都是一知半解的,所以很多名词都没有理解,另外具体的Java虚拟机如何工作还需要后续的学习,这里只能慢慢学习了,等到这本书看完好好读读操作系统的东西 ...

  5. golang data race 竞态条件

    golang race condition 竞态条件 data race race condition golang race detector golang的协程机制使得编写并发代码变得非常容易,但 ...

  6. 竞态条件的赋值_信号-sunshine225-51CTO博客

    一.基础知识信号产生的条件 a. 终端按键产生.如:ctrl+c(SIGINT信号),ctrl+\(SIGQUIT信号),ctrl+z(SIGTSTP信号)...... b. 系统命令和函数.如:ki ...

  7. 谈谈对“竞态条件”和“数据竞争”的理解

    在<JAVA并发编程实战>中提到两个术语:"竞态条件"和"数据竞争". 当时确实没看懂这两个东西有啥区别,我觉得最大的问题在于作者用鸡蛋去解释鸡蛋的 ...

  8. 计算机系统学习之(1):基础知识概要——进程、中断、线程、竞态条件、关键区域、死锁、进程调度

    文章目录 进程的创建 哪些事件导致进程的创建 fork 和 exec 命令创建和控制进程 fork() 命令 execve() 命令 进程的状态 中断 中断的种类 线程 线程共享内容 线程独有内容 进 ...

  9. 竞态条件的赋值_《Java并发编程实战》读书笔记一:基础知识

    一.线程安全性 一个对象是否是需要是线性安全的,取决于它是否需要被多个线程访问 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要额外的同步,这个 ...

最新文章

  1. html false插件,解析webpack插件html-webpack-plugin
  2. sqlserver中能用when_sqlserver中if语句顶替when.case.语句
  3. strncpy——字符串的复制(复制前n个字符)
  4. 新版本springboot-整合mybatis
  5. java学习(80):GULqq界面
  6. Usaco2012-2013 金组 题解 (暂缺Hill walk以及Figue eight)
  7. ENVI5.3sp1下载链接以及安装全过程
  8. 线性代数系列(八)--线性代数和图论
  9. 一种人机友好的视频压缩方案(HMFVC)
  10. 创建文件夹 java_java文件操作 之 创建文件夹路径和新文件
  11. 计算机方向kade期刊,计算机辅助导航技术在上颌骨肿瘤切除及缺损重建中的应用...
  12. 【PyTorch】高级神经网络结构
  13. 云运维拓扑图_云运维的核心是什么?
  14. 来自灵魂的拷问——知道什么是SQL执行计划吗?
  15. i 标签怎么关闭_中山不干胶标签生产厂家——飞盛条码标识技术
  16. 【快速因数分解】Pollard's Rho 算法
  17. GCM Google官方示例的简单介绍和使用
  18. 把css样式表与html网页关联的方法,Dreamweaver 教程-CSS样式表的3种关联方法
  19. 新浪微博瘫痪近一小时无法登陆,现已恢复
  20. 基于SSM和Boostrap实现的电影评论网站设计 毕业论文+外文翻译及原文+项目源码

热门文章

  1. 微服务gomicro搭建
  2. [AWT] 常用组件
  3. 前端高频面试题-非框架
  4. 基因组大数据变异检测算法的并行优化
  5. 怎么注册自己公司域名的企业邮箱?外贸邮箱哪个好用?
  6. 好消息!IBM技术商用 家乐福食品可追溯 商权让消费增值
  7. c语言中if( k1)的含义,C语言:我的按键程序K1键按下没有反应,其他两个都有反应...
  8. git commit 提交报错 husky > pre-commit 问题
  9. 解析程序化中的机器人的算法写作
  10. 【QGIS入门实战精品教程】10.2:QGIS中DEM三维显示方法