第一章总结(温故而知新)
2012-11-20 16:54
120 查看
第一章其实就是一个小引子,介绍了一些必要的基础知识,有很多东西以前不知道,不过看了以后知道了。
Linux多线程的相应函数
当线程1执行完第一条指令后,线程2执行,导致最后线程1完成后产生错误的结果:0。
1.解决办法就是使用锁,相关锁的行为总结有:
2.使用可重入函数
可重入函数主要用于多任务环境中,一个可重入的函数是可以在执行的任何时刻被中断的函数,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。重入就是指重复进入,意味着函数可以被中断,其次以为其除了使用自己栈上的变量以外不依赖任何环境,其函数允许多个函数副本运行,而且使用的是分离栈,故不会互相干扰。要访问全局变量时,应通过关中断,信号量等来加以保护。可重入函数的特点是:
●不使用任何(局部)静态或全局非const变量
●不反悔任何(局部)静态或全局非const变量指针
●仅依赖调用方提供的参数
●不依赖任何单个资源的锁(Mutex)
●不调用任何不可重入函数
使用锁后由于编译器的过度优化也会产生相应错误:代码如下:
这个代码虽然进行了锁的应用,但是由于编译器的优化,并不会按照代码的那种执行方法进行操作,就会好像没有锁一样,又会产生错误,可以使用volatile关键字阻止过度优化:
(1)阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回(比如上一个程序中Thread1的x虽然lock了,但是优化后其执行顺序在Thread2的程序执行之后)
(2)阻止编译器调整操作volatile变量的指令顺序
书上附带了一个Singleton模式的程序作为举例:关于设计模式推荐一本书《大话设计模式》,这个入门还挺好
●在内存位置上调用构造函数
●将内存地址赋值给pInst
经过顺序颠倒后,先进行了内存地址赋值给指针,并没有执行构造函数,另一个GetInstance的并发调用可能会产生错误,此错误可以使用CPU提供的barrier指令阻止换序:
混杂的一些知识:
由于CPU核心频率的提升,内存逐渐跟不上CPU的速度,所以有了和内存频率一致的系统总线,当有了3D游戏和多媒体的发展,慢速的I/O总线不能满足大量的数据交换,所以设计了高速北桥芯片,从而使之可以高速交换数据。有的又跟不上这种高速,然后就出现专门处理低速设备的南桥新品啊。磁盘,USB,键盘,鼠标等就是低速设备,让南桥芯片进行汇总就能连高速北桥了。科技的发展到现在,操作系统现在是分配给进程较短时间,然后CPU通过多进程快速切换,从而看起来好像是同时运行。为了让引荐生产厂商能够对不同的操作系统都能开发不同设备驱动,操作系统开发人员需要为硬件生产厂商提供接口和框架,按这个标准进行开发的程序就能够在相应的操作系统上用了。x86的平台上,有65536个硬件端口寄存器,也就是2的16次方个硬件端口寄存器,为了提高内存空间的应用,就采用了虚拟地址技术,相当于隔了个能够帮你找到能用的物理地址的中间层,让你面对中间层进行操作。Linux的多线程简述
附带书里的代码用于复习:系统调用 | 作用 |
---|---|
fork | 复制当前的进程 |
exec | 使用新的可执行影响覆盖 当前可执行映像 |
clone | 创建子进程并从指定位置开始执行 |
pid_t pid; if(pid=fork()) { ..... }fork函数调用之后,新的任务将启动并和本任务一起从fork函数返回,但是本任务的fork将返回新任务pid,新任务的fork返回0,此方法产生热舞速度快,现任务和原任务共享写时复制(Copy on Write ,COW),意思就是只有新的任务里有不同于就任务的内存改变时才会有新的空间开辟,fork只是复制了个镜像,因此要配合exec函数并通过exec函数执行新的可执行文件。并且还可以使用clone函数产生新线程。关于clone函数简述可以看看这个http://blog.csdn.net/haiyan0106/archive/2007/11/19/1891907.aspx,clone的函数原型:
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
线程的安全:
多个线程同时访问一个共享数据就可能会造成很恶劣的后果,一个线程不知道另一个线程的改变,或者是在并行的时候被另一个线程改变,当前线程就会产生数据操作上的错误,例如:线程1 | 线程2 |
---|---|
i=1; | --i; |
++i; |
1.解决办法就是使用锁,相关锁的行为总结有:
读写锁状态 | 以共享方式获取 | 以独占方式获取 |
---|---|---|
自由 | 成功 | 成功 |
共享 | 成功 | 等待 |
独占 | 等待 | 等待 |
可重入函数主要用于多任务环境中,一个可重入的函数是可以在执行的任何时刻被中断的函数,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。重入就是指重复进入,意味着函数可以被中断,其次以为其除了使用自己栈上的变量以外不依赖任何环境,其函数允许多个函数副本运行,而且使用的是分离栈,故不会互相干扰。要访问全局变量时,应通过关中断,信号量等来加以保护。可重入函数的特点是:
●不使用任何(局部)静态或全局非const变量
●不反悔任何(局部)静态或全局非const变量指针
●仅依赖调用方提供的参数
●不依赖任何单个资源的锁(Mutex)
●不调用任何不可重入函数
使用锁后由于编译器的过度优化也会产生相应错误:代码如下:
x=0; Thread1 Thread2 lock(); lock(); x++; x++; unlock(); unlock();
这个代码虽然进行了锁的应用,但是由于编译器的优化,并不会按照代码的那种执行方法进行操作,就会好像没有锁一样,又会产生错误,可以使用volatile关键字阻止过度优化:
(1)阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回(比如上一个程序中Thread1的x虽然lock了,但是优化后其执行顺序在Thread2的程序执行之后)
(2)阻止编译器调整操作volatile变量的指令顺序
书上附带了一个Singleton模式的程序作为举例:关于设计模式推荐一本书《大话设计模式》,这个入门还挺好
volatile T* pInst=0; T* GetInstance() { if(pInst==NULL) { lock(); if(pInst==NULL) pInst=new T; unlock(); } return pInst; }此代码之所以有问题,因为C++new的步骤中有两个步骤顺序可以颠倒:
●在内存位置上调用构造函数
●将内存地址赋值给pInst
经过顺序颠倒后,先进行了内存地址赋值给指针,并没有执行构造函数,另一个GetInstance的并发调用可能会产生错误,此错误可以使用CPU提供的barrier指令阻止换序:
#define barrier() _asm_volatile ("lwsync")//内嵌汇编 volatile T*pInst=0; T* GetInstance() { if(!pInst) { lock(); if(!pInst) { T* temp=new T; //barrier();CPU的阻止换序指令 pInst=temp; } unlock(); } return pInst; }三种线程模型图形图:表示的是用户使用的线程和内核线程使用的对应关系,其中Linux中的clone产生的线程就是一对一线程。
相关文章推荐
- 软件工程第一章总结
- 高等数学第一章重点总结
- linux设备驱动程序:第一章总结
- 《计算机网络》第七版第一章总结及部分课后习题答案
- 第一章学习总结
- 《信息检索导论》第一章总结
- Java 学习 第一章 java基础语法总结
- [APUE]第一章UNIX基础知识总结
- linux 鸟哥的私房菜(第三版)每章总结 第一章 计算机基础知识
- 数据结构与程序设计 第一章 编程原理 总结
- 数据结构与程序设计第一章总结
- Android开发探索第一章 Activity生命周期及启动模式总结(三)
- TEC1701.WebADI开发技术总结 - 第一章 Step1 - Web ADI客户化开发设置(1/6)
- 蓝书第一章刷题总结
- thinking in java 第一章对象导论总结
- 深入理解计算机第一章总结
- 数电知识点总结第一章:数制和码制
- 有关数据结构(第一章自我总结)
- C# 第一章课后总结
- Linux 第一章(总结)