开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

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

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


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

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

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

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

[复制链接]

结帖率:100% (5/5)
发表于 2012-6-27 10:51:19 | 显示全部楼层 |阅读模式   山西省临汾市
   在多线程存在的环境中,除了堆栈中的临时数据之外,所有的数据都是共享的。如果我们需要线程之间正确地运行,那么务必需要保证公共数据的执行和计算是正确的。简单一点说,就是保证数据在执行的时候必须是互斥的。否则,如果两个或者多个线程在同一时刻对数据进行了操作,那么后果是不可想象的。
    也许有的朋友会说,不光数据需要保护,代码也需要保护。提出这个观点的朋友只看到了数据访问互斥的表象。在程序的运行空间里面,什么最重要的呢?代码吗?当然不是。代码只是为了数据的访问存在的。数据才是我们一切工作的出发点和落脚点。
    那么,有什么办法可以保证在某一时刻只有一个线程对数据进行操作呢?四个基本方法:
    (1)关中断
    (2)数学互斥方法
    (3)操作系统提供的互斥方法
    (4)cpu原子操作
    为了让大家可以对这四种方法有详细的认识,我们可以进行详细的介绍。

    (1)关中断
    要让数据在某一时刻只被一个线程访问,方法之一就是停止线程调度就可以了。那么怎样停止线程调度呢?那么关掉时钟中断就可以了啊。在X86里面的确存在这样的两个指令,
  1. [cpp] view plaincopyprint?#include <stdio.h>   
  2.    
  3. int main()   
  4. {   
  5.     __asm{   
  6.         cli   
  7.         sti   
  8.     }   
  9.     return 1;   
  10. }  
复制代码
其中cli是关中断,sti是开中断。这段代码没有什么问题,可以编过,当然也可以生成执行文件。但是在执行的时候会出现一个异常告警:Unhandled exception in test.exe: 0xC0000096:  Privileged Instruction。告警已经说的很清楚了,这是一个特权指令。只有系统或者内核本身才可以使用这个指令。
    不过,大家也可以想象一下。因为平常我们编写的程序都是应用级别的程序,要是每个程序都是用这些代码,那不乱了套了。比如说,你不小心安装一个低质量的软件,说不定什么时候把你的中断关了,这样你的网络就断了,你的输入就没有回应了,你的音乐什么都没有了,这样的环境你受的了吗?应用层的软件是千差万别的,软件的水平也是参差不齐的,所以系统不可能相信任何一个私有软件,它相信的只是它自己。

    (2)数学方法
    假设有两个线程(a、b)正要对一个共享数据进行访问,那么怎么做到他们之间的互斥的呢?其实我们可以这么做,
  1. [cpp] view plaincopyprint?unsigned int flag[2] = {0};   
  2. unsigned int turn = 0;   
  3.    
  4. void process(unsigned int index)   
  5. {   
  6.     flag[index] = 1;   
  7.     turn =  index;   
  8.    
  9.     while(flag[1 - index] && (turn ==  index));   
  10.     do_something();   
  11.     flag[index] = 0;   
  12. }  
复制代码
其实,学过操作系统的朋友都知道,上面的算法其实就是Peterson算法,可惜它只能用于两个线程的数据互斥。当然,这个算法还可以推广到更多线程之间的互斥,那就是bakery算法。但是数学算法有两个缺点:
    a)占有空间多,两个线程就要flag占两个单位空间,那么n个线程就要n个flag空间,
    b)代码编写复杂,考虑的情况比较复杂

    (3)系统提供的互斥算法
    系统提供的互斥算法其实是我们平时开发中用的最多的互斥工具。就拿windows来说,关于互斥的工具就有临界区、互斥量、信号量等等。这类算法有一个特点,那就是都是依据系统提高的互斥资源,那么系统又是怎么完成这些功能的呢?其实也不难。
    系统加锁过程,
  1. [cpp] view plaincopyprint?void Lock(HANDLE hLock)   
  2. {   
  3.     __asm {cli};   
  4.    
  5.     while(1){   
  6.         if(/* 锁可用*/){   
  7.             /* 设定标志,表明当前锁已被占用 */   
  8.             __asm {sti};   
  9.             return;   
  10.         }   
  11.    
  12.         __asm{sti};   
  13.         schedule();   
  14.         __asm{cli};   
  15.     }   
  16. }  
复制代码
系统解锁过程,
  1. print?void UnLock(HANDLE hLock)   
  2. {   
  3.     __asm {cli};   
  4.     /* 设定标志, 当前锁可用 */   
  5.     __asm{sti};   
  6. }  
复制代码
上面其实讨论的就是一种最简单的系统锁情况。中间没有涉及到就绪线程的压入和弹出过程,没有涉及到资源个数的问题,所以不是很复杂。朋友们仔细看看,应该都可以明白代码表达的是什么意思。

    (4)CPU的原子操作
    因为在多线程操作当中,有很大一部分是比较、自增、自减等简单操作。因为需要互斥的代码很少,所以使用互斥量、信号量并不合算。因此,CPU厂商为了开发的方便,把一些常用的指令设计成了原子指令,在windows上面也被称为原子锁,常用的原子操作函数有
  1. print?InterLockedAdd   
  2.    
  3. InterLockedExchange   
  4.    
  5. InterLockedCompareExchange   
  6.    
  7. InterLockedIncrement   
  8.    
  9. InterLockedDecrement   
  10.    
  11. InterLockedAnd   
  12.    
  13. InterLockedOr  
复制代码

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

使用道具 举报

结帖率:40% (2/5)
发表于 2012-9-10 15:16:55 | 显示全部楼层   台湾省台北市
正在理解中 能解决多线程减少占用cpu吗?
回复 支持 反对

使用道具 举报

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

本版积分规则 致发广告者

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

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

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