锁<锁用来保护的是数据而非代码>(程序员的自我修养)
同步与互斥:
同步:对多个相关进程在执行次序上进行协调,使并发指向的诸进程之间能按照一定的规则共享系统资源,并能很好的相互合作,从而来保证程序的执行可再现性
互斥:一个时间段内,只能有一个进程访问这个资源,资源的排他性。区别与同步,诸进程间可以无序访问
信号量和互斥锁的区别:
<1>互斥量值只能为0/1,信号量值可以为非负整数(一个信号量封锁的区域,可以允许多个进程进入)
<2>互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到
为什么提供锁:硬件底层没有提供这样一种的原子操作:检测--赋值。 我所知道的三种手段:新提供的硬件原子指令, 关中断, 总线封锁
忙等待 空闲等待 是否形成队列
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
锁:OS中描述的互斥手段:
硬件同步机制:忙等
关中断:关中断不适用于多核处理器,一个cpu上关中断,不能防止进程在另一个处理器上访问共享变量-----自旋锁
利用test-and-set指令互斥
利用swap指令实现进程的互斥 XCHG
信号量机制:
整型信号量 忙等
记录型信号量 等待队列 block使进程阻塞 wakeup唤醒进程 多个进程共享一个临界资源
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
自旋锁(常规自旋锁,读写锁)spinlock 忙等待 (锁的粒度?)
自旋锁--适用于执行量少的代码,减少上下文切换
读写锁:可以多个线程进入读操作,但只允许一个线程进行写操作。不允许递归,一个时刻只能一个线程持有该锁
自旋锁在单处理器不可抢占条件下什么也不做
自旋锁在单处理器可抢占条件下禁止中断
自旋锁在多处理器下对总线进行封锁,获得自旋锁才能去访问总线
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一般情况下的线程间的同步方式:
信号量(信号量,使用者数量的不同:互斥信号量、计数型信号量<PV操作>,读写信号量) (信号量有两种,sem_init , sem_wait, sem_post, sem_destroy, semop, semctl, sem) 具有阻塞和非阻塞两种
如果有使用锁的,保存现场进入睡眠,将自己插入等待队列,如果锁释放就会唤醒该进程,需要进行现场保护恢复等操作
信号量不同于自旋锁,不会禁止内核抢占,所以持有信号量的代码可以被抢占
信号量可以同时允许任意数量的锁持有者,而自旋锁一个时刻只能一个任务持有
当获取不成功的时候,任务会将自身放入一个队列中睡眠,指导信号量被释放才唤醒下一个进程,必须在能睡眠的进程中使用。
互斥量: Linux高性能服务器编程中,互斥锁提供了一套属性设置,通过设置属性提供了四种不同的锁
1> 同信号量一样,资源仅同时允许一个线程访问,但和信号量不同的是,信号量在整个系统中可以被任意的线程获取并释放,即同一信号量可以被系统中的一个线程获取之后由另一个线程释放,而互斥量则要求那个线程获取到了互斥量,那个线程要负责释放这个锁,其它线程去释放是无效的
2>互斥量也是有属性设置的,可以实现进程间的共享,但是要看具体的操作系统是否支持
3>如果是普通互斥锁,对已经加锁的互斥锁再次加锁会引起死锁
条件变量: 如果说互斥锁是用于同步线程对共享数据的访问的话,那么条件变量则是用于在线程之间同步共享数据的值。条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
自旋锁spinlock:底下分为四种,分别是普通锁,关闭硬中断(是否保存现场),软中断等来实现。
1>自旋锁底下支持读写锁,读的时候可以多个线程获得锁,写的时候只能一个任务获得该锁
2>没有获得该锁的线程处于忙等待,所以使用该锁的代码要少
3>在获取该锁的时候不能有改变进程状态的代码,否则该进程的状态改变需要等待
4>在单处理器上,如果操作系统允许抢占那自旋锁就相当于禁止抢占,否则自旋锁相当于没有。在多处理器上自旋锁只能禁止一个处理器上的中断,但是不能保证该任务在别的处理器上运行。
5>不能在一段代码下连续两次获得自旋锁。否则将陷于死锁状态
互斥量: 同信号量一样,资源仅同时允许一个线程访问,但和信号量不同的是,信号量在整个系统中可以被任意的线程获取并释放,即同一信号量可以被系统中的一个线程获取之后由另一个线程释放,而互斥量则要求那个线程获取到了互斥量,那个线程要负责释放这个锁,其它线程去释放是无效的
1>同信号量,将等待进程加入队列,在linux下线程和进程的区别不是很明显,用户线程和内核线程是一对一的,所以由操作系统来调度线程,所以在加入等待队列后,由操作系统进程唤醒
2>信号量具有死锁的风险
3>同自旋锁比较,自旋锁用于上下文切换的操作比较少,但是互斥量要进行保护恢复等操作,所以在等待时间较短的情况下使用自旋锁,等待时间较长的情况下使用互斥量
信号量:semphere Dijistra v进化之路漫长
1>记录型型号量,信号量集。刚开始的信号量要使用忙等待,后来在记录型信号量中,,直到
2>信号量:通过设置属性,可以达到进程之间线程之间的同步工作
int sem_init(sem_t *sem, int pshared, unsined value);//通过设置pshared来控制是当前进程的局部信号量还是多个进程之间共享的
3>信号量区别互斥量的地方,互斥量相当于信号互斥量,只能允许加锁,解锁对一个资源的同步, 但是信号量可以允许对多个资源的同步互斥
《信号量的底层使用到自旋锁,禁止中断以及保护现场,在未获得锁的过程中,未获得锁的进程设置timeout插入等待队列进行睡眠schedule_timeout(timeout),进行睡眠,在timeout之后 醒来进行检测锁是否释放,锁的释放通过schedule进行调度。否则继续睡眠》