开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 2782|回复: 2
收起左侧

[C#图文教程] 转载 多线程的那点儿事(之数据同步)

[复制链接]

结帖率:100% (5/5)
发表于 2012-6-27 10:48:46 | 显示全部楼层 |阅读模式   山西省临汾市
    多线程创建其实十分简单,在windows系统下面有很多函数可以创建多线程,比如说_beginthread。我们就可以利用它为我们编写一段简单的多线程代码,
  1. [cpp] view plaincopyprint?#include <windows.h>   
  2. #include <process.h>   
  3. #include <stdio.h>   
  4.    
  5. unsigned int value = 0;   
  6.    
  7. void print(void* argv)   
  8. {   
  9.     while(1){   
  10.         printf("&value = %x, value = %d\n", &value, value);   
  11.         value ++;   
  12.         Sleep(1000);   
  13.     }   
  14. }   
  15.    
  16. int main()   
  17. {   
  18.     _beginthread( print, 0, NULL );   
  19.     _beginthread( print, 0, NULL);   
  20.    
  21.     while(1)   
  22.         Sleep(0);   
  23.    
  24.     return 1;   
  25. }  
复制代码
注意,在VC上面编译的时候,需要打开/MD开关。具体操作为,【project->setting->c/c++->CategoryCode Generation->Use run-time library->Debug Multithreaded】即可。
    通过上面的示例,我们看到作为共享变量的value事实上是可以被所有的线程访问的。这就是线程数据同步的最大优势——方便,直接。因为线程之间除了堆栈空间不一样之外,代码段和数据段都是在一个空间里面的。所以,线程想访问公共数据,就可以访问公共数据,没有任何的限制。
    当然,事物都有其两面性。这种对公共资源的访问模式也会导致一些问题。什么问题呢?我们看了就知道了。
    现在假设有一个池塘,我们雇两个人来喂鱼。两个人不停地对池塘里面的鱼进行喂食。我们规定在一个人喂鱼的时候,另外一个人不需要再喂鱼,否则鱼一次喂两回就要撑死了。为此,我们安装了一个牌子作为警示。如果一个人在喂鱼,他会把牌子设置为FALSE,那么另外一个人看到这个牌子,就不会继续喂鱼了。等到这个人喂完后,他再把牌子继续设置为TRUE
    如果我们需要把这个故事写成代码,那么怎么写呢?朋友们试试看,
  1. print?while(1){   
  2.     if( flag == true){   
  3.         flag = false;   
  4.         do_give_fish_food();   
  5.         flag = true;   
  6.     }   
  7.    
  8.     Sleep(0);   
  9. }  
复制代码
上面的代码看上去没有问题了,但是大家看看代码的汇编代码,看看是不是存在隐患。因为还会出现两个人同时喂食的情况,
  1. [cpp] view plaincopyprint?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 [__imp__Sleep@4 (004361c4)]   
  20. 0040111D   cmp         esi,esp   
  21. 0040111F   call        __chkesp (004011e0)   
  22. 31:       }   
  23. 00401124   jmp         do_action+18h (004010e8)   
  24. 32:   }  
复制代码
我们此时假设有两个线程ab在不停地进行判断和喂食操作。设置当前flag = true,此时线程a执行到004010F8处时,判断鱼还没有喂食,正准备执行指令004010F8,但是还没有来得及对falg进行设置,此时出现了线程调度。线程b运行到004010F8时,发现当前没有人喂食,所以执行喂食操作。等到b线程喂食结束,运行到00401113的时候,此时又出现了调度。线程a有继续运行,因为之前已经判断了当前还没有喂食,所以线程a继续进行了喂食了操作。所以,可怜的鱼,这一次就连续经历了两次喂食操作,估计有一部分鱼要撑死了。
    当然鱼在这里之所以会出现撑死的情况,主要是因为line 24line 25之间出现了系统调度。所以,我们在编写程序的时候必须有一个牢固的思想意识,如果缺少必须要的手段,程序可以任何时刻任何地点被调度,那此时公共数据的计算就会出现错误。

结帖率:61% (35/57)
发表于 2012-7-11 06:18:26 | 显示全部楼层   海南省乐东黎族自治县
好东西。是支持来的
回复 支持 反对

使用道具 举报

发表于 2012-12-15 23:58:10 | 显示全部楼层   **
这个是C#??
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表