Chinaunix首页 | 论坛 | 博客
  • 博客访问: 228474
  • 博文数量: 40
  • 博客积分: 2025
  • 博客等级: 大尉
  • 技术积分: 531
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-25 17:47
文章分类

全部博文(40)

文章存档

2010年(8)

2009年(32)

我的朋友

分类: LINUX

2010-04-20 21:45:28

作者: good bai   

一 同步锁机制和原子操作 
同步锁机制 

1 互斥量 metux,使用较多的一种枷锁机制,在申请锁失败后便阻塞当前线程执行,直到锁可用时重新被激活运行而获得锁。在竞争频发的情况下,性能比自旋锁好的多。 

2 自旋锁 spinlock ,申请锁失败后,循环申请直到获得锁,优点是竞争较少的场景下,减少了阻塞和激活请求线程时多余的系统开销。自旋锁保持期间是抢占失效的,而互斥量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。 

3 条件变量 ,在两个线程同步时使用。 

4 读写锁 ,适合读远大于修改的情况。如果有写锁在阻塞时,不在响应读锁。 

互斥量和自旋锁区别 
------------------------------------------------------ 
虽然听起来两者之间的使用条件复杂,其实在实际使用中互斥量和自旋锁并不易混淆。注意以下原则: 
如果代码需要睡眠——这往往是发生在和用户空间同步时——使用互斥量是唯一的选择。由于不受睡眠的限制,使用互斥量通常来说更加简单一些。如果需要在自旋 锁和互斥量中作选择,应该取决于锁被持有的时间长短。理想情况是所有的锁都应该尽可能短的被持有,但是如果锁的持有时间较长的话,使用互斥量是更好的选 择。另外,互斥量不同于自旋锁,它不会关闭内核抢占,所以持有互斥量的代码可以被抢占。这意味者互斥量不会对影响调度反应时间带来负面影响。 


自旋锁对互斥量 
------------------------------------------------------ 
需求 建议的加锁方法 

低开销加锁 优先使用自旋锁 
短期锁定 优先使用自旋锁 
长期加锁 优先使用互斥量 
中断上下文中加锁 使用自旋锁 
持有锁是需要睡眠、调度 使用互斥量 

原子操作 
原子操作,即一条指令可以完成的操作(应该是一条汇编指令可以完成的操作),一般高级语言的程序翻译为机器指令后,往往一条语句需要多条机器码操作来实现。而只有用一条机器指令就可以完成的操作所对应的语句,我们可以称且为原子操作。比如: 

a=a+1 
对应的汇编码 (汇编码等同于机器指令) 
mov a的地址 寄存器 
add 寄存器 1 
mov 寄存器 a的地址 


a=1 
汇编码 
mov a的地址 1 

上面的2示例的操作为原子操作,一条语句是否为原子操作,和硬件实现有关,对intel平台就需要查询intel相关的技术规格说明书。一些操作默认被认为是原子操作,如:对齐的内存寻址操作等(据说位操作不属于原子操作),还有一些补充的“硬件功能”可以实现一些必要的原子操作(具体参考引文)。除了这一些,更多的同步要求,就得使用线程锁机制了。 


二 关于多进程/线程的一点理解 

fork 与vfork的区别 
vfork现在只是在部分的unix系统中存在,最早出现vfork是因为fork创建的子进程要完全复制一份父进程的资源,系统开销太大,而vfork则只是共享使用父进程的资源。现在的fork已采用写时复制(copy-on write)技术,只当有数据改变时才会生成新的块。所以一般来讲vfork已经没有了存在的必要。 

另外,还有一点差别是,vfork在建立子进程后会阻塞父进程,直到子进程退出或者执行了exec类调用和重新激活。 

exit与_exit 
在子进程中要小心使用_exit结束进程执行,如果使用exit会发生错误。一个main函数只能执行一次exit退出,这是因为exit在退出时会做一些默认定义的现场清理工作。当某一线程执行完成后,使用_exit退出即可,而只有在主进程执行结束时,需要调用exit完成所有当前程序退出前的善后工作。 

linux内核不支持线程调度,它的线程是轻量级进程(Light-Weight Process),每一个线程与内核中进程调度是一一对应的(所以在打印同一进程中不同线程的父进程时pid却是不一样的情况,这是因为linux的clone函数对CLONE_PID参数的实现不完全所致),一般来说进程在建立和调度时的系统开销比较大,但linux对进程的实现做了优化,尤其是写时复制技术(copy-on write)大大提高了进程进程创建的系统开销。linux中在使用clone创建线程时,会传递参数CLONE_VM,CLONE_FS,CLONE_SIGHAND等参数,直接让新线程共享了进程的资源。 

windows的线程模型和linux有很大差异,因为windows的进程的系统开销很大,所以MS采用了完全独立结构实现线程模型。 

内核线程是为更好的并发多处理机,但在线程调度时系统开销较大;用户空间线程则是为减少上下文调度开销,但由于线程的调度完全在用户态进行,在内核之外,所以不利于发挥多处理的并发使用,而现在多处理机系统并发的要求则越来越多。而混合搭配则可能带来更大的好处。但Linux采用的是完全的内核线程模型,一条内核线程(实际是LWP)对应一条用户线程,这样在较高的线程调度开销问题如何解决?(linux着重优化了轻量级进程的调度) 

参考:
http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ Linux 线程实现机制分析 
杨沙洲 (
)国防科技大学计算机学院

参考1: 
多线程程序中操作的原子性 
 
信号量和自旋锁(ZHUAN) 
http://blog.chinaunix.net/u1/38576/showart_367985.html 
Intel X86 CPU编程参考手册 
阅读(1348) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~