多线程的那点儿事(之数据同步)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

多线程创建其实十分简单,在windows系统下面有很多函数可以创建多线程,比如说_beginthread。我们就可以利用它为我们编写一段简单的多线程代码,

[cpp] view plaincopy

  1. #include <windows.h>
  2. #include <process.h>
  3. #include <stdio.h>
  4. unsigned int value = 0;
  5. void print(void* argv)
  6. {
  7. while(1){
  8. printf("&value = %x, value = %d\n", &value, value);
  9. value ++;
  10. Sleep(1000);
  11. }
  12. }
  13. int main()
  14. {
  15. _beginthread( print, 0, NULL );
  16. _beginthread( print, 0, NULL);
  17. while(1)
  18. Sleep(0);
  19. return 1;
  20. }

注意,在VC上面编译的时候,需要打开/MD开关。具体操作为,【project】->【setting】->【c/c++】->Category【Code Generation】->【Use run-time library】->【Debug Multithreaded】即可。

通过上面的示例,我们看到作为共享变量的value事实上是可以被所有的线程访问的。这就是线程数据同步的最大优势——方便,直接。因为线程之间除了堆栈空间不一样之外,代码段和数据段都是在一个空间里面的。所以,线程想访问公共数据,就可以访问公共数据,没有任何的限制。

当然,事物都有其两面性。这种对公共资源的访问模式也会导致一些问题。什么问题呢?我们看了就知道了。

现在假设有一个池塘,我们雇两个人来喂鱼。两个人不停地对池塘里面的鱼进行喂食。我们规定在一个人喂鱼的时候,另外一个人不需要再喂鱼,否则鱼一次喂两回就要撑死了。为此,我们安装了一个牌子作为警示。如果一个人在喂鱼,他会把牌子设置为FALSE,那么另外一个人看到这个牌子,就不会继续喂鱼了。等到这个人喂完后,他再把牌子继续设置为TRUE。

如果我们需要把这个故事写成代码,那么怎么写呢?朋友们试试看,

[cpp] view plaincopy

  1. while(1){
  2. if( flag == true){
  3. flag = false;
  4. do_give_fish_food();
  5. flag = true;
  6. }
  7. Sleep(0);
  8. }

上面的代码看上去没有问题了,但是大家看看代码的汇编代码,看看是不是存在隐患。因为还会出现两个人同时喂食的情况,

[cpp] view plaincopy

  1. 23:       while(1){
  2. 004010E8   mov         eax,1
  3. 004010ED   test        eax,eax
  4. 004010EF   je          do_action+56h (00401126)
  5. 24:           if( flag == true){
  6. 004010F1   cmp         dword ptr [flag (00433e04)],1
  7. 004010F8   jne         do_action+43h (00401113)
  8. 25:               flag = false;
  9. 004010FA   mov         dword ptr [flag (00433e04)],0
  10. 26:               do_give_fish_food();
  11. 00401104   call        @ILT+15(do_give_fish_food) (00401014)
  12. 27:               flag = true;
  13. 00401109   mov         dword ptr [flag (00433e04)],1
  14. 28:           }
  15. 29:
  16. 30:           Sleep(0);
  17. 00401113   mov         esi,esp
  18. 00401115   push        0
  19. 00401117   call        dword ptr [[email protected] (004361c4)]
  20. 0040111D   cmp         esi,esp
  21. 0040111F   call        __chkesp (004011e0)
  22. 31:       }
  23. 00401124   jmp         do_action+18h (004010e8)
  24. 32:   }

我们此时假设有两个线程a和b在不停地进行判断和喂食操作。设置当前flag = true,此时线程a执行到004010F8处时,判断鱼还没有喂食,正准备执行指令004010F8,但是还没有来得及对falg进行设置,此时出现了线程调度。线程b运行到004010F8时,发现当前没有人喂食,所以执行喂食操作。等到b线程喂食结束,运行到00401113的时候,此时又出现了调度。线程a有继续运行,因为之前已经判断了当前还没有喂食,所以线程a继续进行了喂食了操作。所以,可怜的鱼,这一次就连续经历了两次喂食操作,估计有一部分鱼要撑死了。

时间: 2024-10-08 05:05:17

多线程的那点儿事(之数据同步)的相关文章

Delphi中多线程用消息实现VCL数据同步显示

Delphi中多线程用消息实现VCL数据同步显示 Lanno Ckeeke 2006-5-12 概述: delphi中严格区分主线程和子主线程,主线程负责GUI的更新,子线程负责数据运算,当数据运行完毕后,子线程可以向主线程式发送消息,以便通知其将VCL中的数据更新. 实现: 关键在于消息的发送及接收.在消息结构Tmessage中wParam和lParam类型为Longint,而指针类型也定义为Longint,可以通过此指针来传递自己所感兴趣的数据.如传递字符数组: 数组定义: const MA

Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解

   我们知道在多线程编程中,我们很大的一部分内容是为了解决线程间的资源同步问题和线程间共同协作解决问题.线程间的同步,通俗我们理解为僧多粥少,在粥有限情况下,我们怎么去防止大家有秩序的喝到粥,不至于哄抢都没得喝.线程讲协作,我们可以理解为我们在医院看病的时候,我们要先挂号,才能看病.现在医院有很多病人排队,怎么协调病人都有秩序的先挂号,后看病.本篇文章的重点不在此,也不是在此一下子能分析完,我们先从Java JVM的角度来理解多线程的一些方面. 我们知道多线程间的数据同步,我们是通过加锁的操作

Java多线程初学者指南(9):为什么要进行数据同步

http://www.blogjava.net/nokiaguy/archive/2009/nokiaguy/archive/2009/03/archive/2009/03/19/260753.html Java中的变量分为两类:局部变量和类变量.局部变量是指在方法内定义的变量,如在run方法中定义的变量.对于这些变量来说,并不存在线程之间共享的问题.因此,它们不需要进行数据同步.类变量是在类中定义的变量,作用域是整个类.这类变量可以被多个线程共享.因此,我们需要对这类变量进行数据同步. 数据同

volatile足以保证数据同步吗

上一节已经了解了java内存模型,JMM为了提高执行性能,引入了工作内存和主存两个概念,在继续讨论之前必须先搞清四种存储介质:寄存器.高级缓存.RAM和ROM. RAM与ROM大家都比较熟悉了,可以看成是我们经常说的内存与硬盘,寄存器属于处理器里面的一部分,而高级缓存cache是CPU设计者为提高性能引入的一个缓存,也可以说是属于处理器的一部分.在利用CPU进行运算时必定涉及操作数的读取,假如CPU直接读取ROM,那么这个读取速度简直是无法忍受的,于是引入了内存RAM,这样做确实让速度提高了很多

线程安全、数据同步之synchronized与Lock

线程安全.数据同步之synchronized与Lock 技术交流1群:46523908 技术交流2群:46505645 NoHttp 源码及Demo托管在Github欢迎大家Star:https://github.com/Y0LANDA/NoHttp NoHttp是专门做Android网络请求与下载的框架. 本文Demo下载传送门 写在前面 本篇文章讲的东西都是Android开源网络框架NoHttp的核心点,当然线程.多线程.数据安全这是Java中就有的,为了运行快我们用一个Java项目来讲解.

Java 线程第三版 第三章数据同步 读书笔记

多线程间共享数据问题 一.Synchronized关键字 atomic一词与"原子"无关,它曾经被认为是物质的最小的单元,不能再被拆解成更小的部分. 当一个方法被声明成synchronized,要执行此方法的thread必须先取得一个token,我们将它称为锁.一旦该方法取得(或者说是获得)锁,它将运行此方法然后释放掉(或者返回)此锁.不管方法时怎样返回的(包括通过异常)该锁会被释放. 二.Volatile关键字 如果变量被标示为volatile,每次使用该变量时都必须从主寄存器中读出

rsync+inotify-tools实时数据同步配置实战

实验环境的准备: 源服务器:10.0.0.130 目标服务器:10.0.0.139 一.在源服务器安装Rsync服务端 1.关闭SELINUX vi /etc/selinux/config #编辑防火墙配置文件 #SELINUX=enforcing #注释掉 #SELINUXTYPE=targeted #注释掉 SELINUX=disabled #增加 :wq! #保存,退出 setenforce 0  #立即生效 2.开启防火墙tcp 873端口(Rsync默认端口) vi /etc/sysc

线程安全、数据同步之 synchronized 与 Lock

本文Demo下载传送门 写在前面 本篇文章讲的东西都是Android开源网络框架NoHttp的核心点,当然线程.多线程.数据安全这是Java中就有的,为了运行快我们用一个Java项目来讲解. 为什么要保证线程安全/数据同步 当多个子线程访问同一块数据的时候,由于非同步访问,所以数据可能被同时修改,所以这时候数据不准确不安全. 现实生活中的案例 假如一个银行帐号可以存在多张银行卡,三个人去不同营业点同时往帐号存钱,假设帐号原来有100块钱,现在三个人每人存钱100块,我们最后的结果应该是100 +

数据同步那些事儿(优化过程分享)

简介 很久之前就像写这篇文章了,主要是介绍一下我做数据同步的过程中遇到的一些有意思的内容,和提升效率的过程. 当前在数据处理的过程中,数据同步如同血液一般充满全过程,如图: 数据同步开源产品对比: DataX,是淘宝的开源项目,可惜不支持Postgresql Sqoop,Apache开源项目,同步过程中字段需要严格一致,不方便扩展,不易于二次开发 整体设计思路: 使用生产者消费者模型,中间使用内存,数据不落地,直接插入目标数据 优化过程: 1.插入数据部分: 首先生产者通过Jdbc获取源数据内容