多线程同步

多线程同步中的几个概念

1.自旋锁与互斥锁

自旋锁与互斥锁类似于轮询与回调,前者不停的请求,后者等待通知

自旋锁:调用者想要获取资源,但是自旋锁被其他线程占用着,调用者就一直在那里自旋询问“好了没?....”,所以起名自旋锁,自旋期间一直占用CPU资源,所以这种低级锁比较适合短时间的保护数据资源或代码片段的方式,而且这种锁容易产生“活锁”(如在一个单CPU的机器上使用自旋锁,占有锁的线程A优先级低于想要获取锁的那个线程B优先级,B就只能不断的自旋请求获取锁,而A却得不到CPU时间片无法执行更无法释放锁,活锁)。

互斥锁:如果资源已经被占用,资源请求者只能进入睡眠状态(不占用CPU资源),等待之后被唤醒。“我睡会,你用完了叫我”。

饥饿:由于某种原因,线程不得不无限期的推迟自己的运行。活锁就是饥饿的一种特殊情形。

优先级反转:就是高优先级的线程反而却要看中优先级的脸色,本来应该是中看高脸色才是;如:有三个线程A、B、C优先级依次为低、中、高,还有一个互斥的资源,假如现在A获取到了资源,刚要开始使用,此时C也想要获取资源(抢占了CPU时间片),但是它必须等待(释放CPU时间片),此时B又开始执行了,但是B不需要获取互斥资源,所以B就一直在哪里执行,A几乎一直在那里等着B(谁让B的优先级高于A呢),所以间接导致了C也无法执行了,也就是C还得看B的脸色了。对应优先级反转解决办法:可以通过优先级继承办法解决,即当一个高优先级C等待低优先级A持有的资源时,将低优先级A暂时提升到高优先级线程的级别,在释放互斥资源后,再降回原来的低优先级别。

死锁:两个或两个以上的进程(线程)在执行的过程中相互等待的过程(争抢资源),死锁和活锁的区别就是,发生死锁的时候,线程会在那里僵住不动(也不会占用CPU),而活锁会一直在请求、尝试、失败。死锁一般无解,除非人工介入杀死其中一个进程(线程),而活锁有可能自行解决,操作系统调度提升有锁的线程优先级。

2.锁:基元构造

windows的同步方式有2种:内核模式构造和用户模式构造,统称基元构造,C#还有个更NB的混合构造,吸取前两者的优点。

内核模式构造锁可以跨进程。waitHandle、信号量、互斥量都是进行线程同步的内核对象。

 

用户模式构造:用特殊的CPU指令来协调线程的,通常都进行原子操作,volatile和interlocked就是一种,用户模式构造速度显著比内核模式构造要快。

 

 

 3.线程安全需要具备以下3个特性:

可见性:说白了就是多线程是不是拿到了最新的值;

原子性:是不是原子操作;

有序性:CPU或编译器有可能重排你的代码,改变代码的执行顺序;

 

posted @ 2021-04-02 15:34  _MrZhu  阅读(71)  评论(0)    收藏  举报