多线程编程之数据访问互斥——原理性
来源:互联网 发布:脉冲爆震发动机 知乎 编辑:程序博客网 时间:2024/06/05 04:01
http://www.cnblogs.com/kuliuheng/p/4062042.html
本文参考文章:多线程的那点事儿(之数据互斥)
在多线程存在的环境中,除了堆栈中的临时数据之外,所有的数据都是共享的。如果我们需要线程之间正确地运行,那么务必需要保证公共数据的执行和计算是正确的。简单一点说,就是保证数据在执行的时候必须是互斥的。否则,如果两个或者多个线程在同一时刻对数据进行了操作,那么后果是不可想象的。
保证多线程之间的数据访问互斥,有以下四类方法:
(1)关中断
(2)数学互斥方法
(3)操作系统提供的互斥方法
(4)CPU原子操作
下面针对这四种方法进行详细说明:
(1)关中断
既然多线程之间的中断切换会导致访问同一数据的不同步,那么关闭线程中断切换肯定能过避免这个问题。而且,Intel X86系列CPU中确实存在这样的关闭中断指令。参照如下代码:
#include <stdio.h> int main() { __asm{ cli sti } return 1; }
其中cli是关中断,sti是开中断。这段代码没有什么问题,可以编过,当然也可以生成执行文件。但是在执行的时候会出现一个异常告警:Unhandled exception in test.exe: 0xC0000096: Privileged Instruction。告警已经说的很清楚了,这是一个特权指令。只有系统或者内核本身才可以使用这个指令。
不过,大家也可以想象一下。因为平常我们编写的程序都是应用级别的程序,要是每个程序都是用这些代码,那不乱了套了。比如说,你不小心安装一个低质量的软件,说不定什么时候把你的中断关了,这样你的网络就断了,你的输入就没有回应了,你的音乐什么都没有了,这样的环境你受的了吗?应用层的软件是千差万别的,软件的水平也是参差不齐的,所以系统不可能相信任何一个私有软件,它相信的只是它自己。简单来说,作为应用程序开发,这个方法肯定是不可取的。
(2)数据方法
通过某个数学算法,可以确保不同的线程之间只可能其中一个访问某个数据。例如有两个线程操作同一个变量,可以采用如下算法:
unsigned int flag[2] = {0};unsigned int turn = 0;void process(unsigned int index){ flag[index] = 1; turn = 1 - index; while(flag[1 - index] && (turn == (1 - index))); do_something(); flag[index] = 0;}
其实,学过操作系统的朋友都知道,上面的算法其实就是Peterson算法,可惜它只能用于两个线程的数据互斥。当然,这个算法还可以推广到更多线程之间的互斥,那就是bakery算法。但是数学算法有两个缺点:
a)占有空间多,两个线程就要flag占两个单位空间,那么n个线程就要n个flag空间;
b)代码编写复杂,考虑的情况比较复杂。
(3)操作系统提供的互斥方法
系统提供的互斥算法其实是我们平时开发中用的最多的互斥工具。就拿windows来说,关于互斥的工具就有临界区、互斥量、信号量等等。这类算法有一个特点,那就是都是依据系统提高的互斥资源,那么系统又是怎么完成这些功能的呢?其实也不难。
举一个最简单的系统锁实现方法:
void Lock(HANDLE hLock){ __asm {cli}; while(1){ if(/* 锁可用*/){ /* 设定标志,表明当前锁已被占用 */ __asm {sti}; return; } __asm{sti}; schedule(); __asm{cli}; }}void UnLock(HANDLE hLock){ __asm {cli}; /* 设定标志, 当前锁可用 */ __asm{sti};}
从代码中可以看出,采用的CPU的中断关闭与开启指令就能够实现一个简单的系统锁。不过这个例子没有考虑就绪线程的压栈等问题,实际情况会更加复杂些。
(4)CPU原子操作
在多线程中经常会涉及到一个经常用到而又非常简单的计算操作,这个时候使用互斥量、信号量等实现互斥操作显得不划算。因此,CPU厂商将一些常用的操作设计成原子指令,在Windows系统中也称之为原子锁。常用的原子操作包括:
InterLockedAddInterLockedExchangeInterLockedCompareExchangeInterLockedIncrementInterLockedDecrementInterLockedAndInterLockedOr
» 下一篇:多线程编程之Windows同步方式
- 多线程编程之数据访问互斥——原理性
- 多线程编程——互斥对象
- Windows多线程编程实现数据互斥访问的几个方法
- 网络编程(38)—— 利用互斥mutex控制多线程对临界区的访问
- 多线程编程(10) - 多线程同步之 Mutex (互斥对象)
- 多线程编程(10) - 多线程同步之 Mutex (互斥对象)
- 多线程编程(10) - 多线程同步之 Mutex (互斥对象)
- linux多线程编程——同步与互斥
- linux多线程编程——同步与互斥
- linux多线程编程——同步与互斥
- 多线程编程—线程的同步与互斥
- linux 多线程编程 之 信号量互斥同步
- linux 多线程编程 之 信号量互斥同步
- linux 多线程编程 之 信号量互斥同步
- linux 多线程编程 之 信号量互斥同步
- 多线程的数据互斥
- 多线程的那点事儿(之数据互斥)
- 多线程那点事儿(之数据互斥)
- 13《将心注入》-豆瓣评分8.3
- JAVA全部消除HTML标签/消除部分HTML标签
- Spring自定义Annotation扫描
- Java编程性能优化技巧有哪些
- 四种博弈浅谈(巴什博弈、威佐夫博弈、妮姆博奕、斐波那契博弈)
- 多线程编程之数据访问互斥——原理性
- 205. Isomorphic Strings
- java中异常及异常处理
- Vue项目中设置背景图片
- USACO section 1.3 Ski Course Design
- 五大应用优先蓝牙
- WEB前端JS弹窗
- 相机坐标,图像坐标,大地物理坐标
- 面试题14. 调整数组顺序使奇数位于偶数前面